'if'语句太多?



下面的代码确实按照我的要求工作,但是它很丑,太过了,或者有很多其他的原因。我看了一些公式,并试图写出一些解决方案,但我最终得到了类似数量的语句。

在这种情况下,是否有一种数学公式对我有益,或者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;
}

如果你不能想出一个公式,你可以使用一个表格来显示有限数量的结果:

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];

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

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问题的函数的本质是从两个数(1,2),域{0,1,2,3}到范围{0,1,2,3}的映射。每个答案都涉及如何实现该映射。

同样,你可以在许多答案中看到问题的重述,即1个2位数的以4为基数的数字N(1,2)的映射,其中一个是数字1,两个是数字2,N = 4* 1 + 2;N ={0,1,2,…16个不同的值,这很重要。该函数的输出是一个以1为基数的4位数{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) &0 x3。表达式(one <<3)和(2)<<1)只是把东西乘出来,同时注意到2*x = x <<1和8*x = x <<3.

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

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

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

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

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]; 
}

其他人已经提出了我最初的想法,即矩阵方法,但是除了合并if语句之外,您还可以通过确保提供的参数在预期范围内并使用就地返回(我见过的一些编码标准强制函数的单点出口)来避免一些问题。但是我发现多次返回对于避免箭头编码非常有用,并且随着Java中异常的流行,严格执行这样的规则没有多大意义,因为方法内部抛出的任何未捕获的异常无论如何都是可能的退出点)。嵌套switch语句是可能的,但是对于您在这里检查的小范围值,我发现if语句更紧凑,不太可能导致太多的性能差异,特别是如果您的程序是基于回合而不是实时的。

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
}

由于input->结果映射部分的不规则性,这最终会导致可读性降低。我更喜欢矩阵风格,因为它很简单,而且你可以把矩阵设置得很有视觉意义(尽管这在一定程度上受到我对卡诺地图的记忆的影响):

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;
}

如果你想添加更多高度的块/攻击,你甚至不需要改变函数本身,只需要枚举;不过,添加其他类型的移动可能需要修改函数。此外,EnumSet s可能比使用额外的枚举作为主枚举的属性更具可扩展性,例如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;
}

另外,用三元操作符(boolean_expression ? result_if_true : result_if_false)替换一些if语句可以使代码更紧凑(例如,前面块中的代码将变成return one.isAttack() ? LandedHit.PLAYER_TWO : LandedHit.PLAYER_ONE;),但这可能导致更难阅读的联机程序,因此我不建议在更复杂的分支中使用它。

为什么不使用数组呢?

我将从头开始。我看到了一个模式,值从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

现在也许你已经看到了一些模式,但是当我组合值1和2时,我看到你正在使用所有值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

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

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},它的索引是1和2的组合。

我不是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是否比乘法快。但这值得一试。

这使用了一点bitmagic(你已经通过保存两位信息(low/high &攻击/阻止)在单个整数中):

我没有运行,只是打在这里,请仔细检查。这个主意确实有效。编辑:现在测试每个输入,工作良好。

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;
    }
}

或者我应该建议将这两个信息位分离到单独的变量中?像上面这样主要基于位操作的代码通常很难维护。

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

您可以嵌套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:你的答案对于P1(参与人1)和P2(参与人2)是对称的。这对格斗游戏来说很有意义,但你也可以利用它来提高你的逻辑。

2:3拍0拍2拍1拍3。这些例子中唯一没有涵盖的情况是0 vs 1和2 vs 3的组合。换句话说,独特的胜利表是这样的:0击败2,1击败3,2击败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 显然意味着;它们不是任意值,所以给它们命名会有帮助。

我希望我正确理解了逻辑。比如:

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;
}

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

编辑:算法没有完全理解,阻塞时"命中"奖励,我没有意识到(谢谢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;
}

我没有Java的经验,所以可能会有一些拼写错误。请将此代码视为伪代码。

我会用一个简单的开关。为此,您需要对单个数字求值。然而,在这种情况下,由于0 <= one < 4 <= 90 <= two < 4 <= 9,我们可以通过将one乘以10并加上two将这两个int型转换为简单的int型。然后在得到的数字中使用如下的开关:

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;
}

还有一个简短的方法,我只是想指出作为理论代码。但是我不会用它,因为它有一些额外的复杂性,你通常不想处理。额外的复杂性来自于基数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];
}

既然您更喜欢嵌套的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;
}

试试与开关外壳。 .

查看此处或此处获取更多信息

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

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

PS:仅当满足一个条件时

如果同时出现2种情况…我不认为开关可以使用。但是你可以在这里减少你的代码。

Java switch语句多重情况

我想到的第一件事基本上是由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的哪些值对应于哪些返回值。

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

您可以使用一个开关箱而不是多个if

还要提一下,既然你有两个变量那么你必须合并这两个变量才能在switch

中使用它们

检查这个Java switch语句来处理两个变量?

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

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

以上将减少至少3个if语句。我没有看到一个固定的模式,也不能从给出的代码中收集到很多东西——但是如果可以派生出这样的逻辑,它将减少许多if语句。

希望这对你有帮助。

最好将规则定义为文本,这样可以更容易地推导出正确的公式。这是从laalto的nice数组表示中提取的:

{ 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命中的一些解释将是伟大的,看起来很有趣!

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

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;
}

不包含任何"魔法"数字;)

我个人喜欢级联三元操作符:

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

所以你可以使用magic:

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

这是一个相当简洁的版本,类似于JAB的响应。这使用了一个地图来存储移动的胜利。

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

我会使用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);
    }
}

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

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

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

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; }
  }
}
  1. 使用常量或枚举使代码更具可读性
  2. 尝试将代码拆分为更多的函数
  3. 尝试使用问题的对称性

这里有一个建议,但在这里使用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并不擅长表达这类数据类型。

不如这样做

   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
    }
    }

最新更新