太多'if'陈述?

Tom*_*rth 260 math if-statement formula

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

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

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

laa*_*lto 599

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

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];
Run Code Online (Sandbox Code Playgroud)

  • @JoeHarper如果你想要一些易于阅读的东西,你将不会首先使用魔术数字,你将有一个解释映射的注释.事实上,我更喜欢这个版本,但是对于长期可维护的东西,我会使用一种涉及枚举类型或至少命名常量的方法. (43认同)
  • @JoeHarper"理论上"是一回事,"实际上"是另一回事.当然,我试图用描述性的命名(与`i` /`j` /`for循环变量k`约定的除外),命名常量,安排我的代码以可读的方式等等,但是当变量和函数名称开始占用超过20个字符,我发现它实际上导致代码不太可读.我通常的方法是尝试可理解但简洁的代码,在这里和那里用注释解释_why_代码的结构与它的结构(与方式相同).把名字中的原因搞得一团糟. (13认同)
  • 我喜欢这个特定问题的解决方案,因为结果实际上是由结果矩阵决定的. (13认同)
  • 这很有趣,因为我以前没见过这个解决方案.我不太确定我理解返回结果但是会喜欢测试. (7认同)
  • 你不需要断言,如果一个或多个索引超出范围,Java将抛出一个`IndexOutOfBoundsException`. (4认同)
  • 将决策转换为这样的数据是一种非常好的重构技术.它有很多不明显的方式!您还应该记住,这可用于切换代码和数据(最后一个数组可以是接口的所有实现,而您的索引语句也可能涉及调用该方法).此外 - 这允许您外部化数据(将其放入文本文件.此外它往往会导致进一步的重构.这只是一个很好的技术知道.如果你真的很难避免切换(你应该),这是一个很好的替代品. (3认同)
  • 对于一个较新的开发人员来说,这将更难以阅读,如果你是唯一一个处理你的代码的人,那很好,但是如果你是一个拥有初级开发人员的团队,那么使用这种方法肯定会损害他们的理解,从而降低可维护性的代码? (2认同)
  • 那么,你不遵循重构代码的惯例,理论上你不需要注释吗?我尝试以这样的形式编写我的代码,它几乎可读作为一个句子.这包括创建具有与其功能完全匹配的名称的方法,具有名称而不是字母的变量,以及其中简单阅读的代码.不要不尊重你的方法,但从我的角度来看,if语句看起来更容易阅读. (2认同)

waT*_*eim 201

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

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

更多按位变体:

这使得事实是一切都是2的倍数

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

魔幻常数的起源

我能说什么?世界需要魔法,有时候需要某种东西来创造它.

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

此外,您可以在一些答案中看到问题的重述,作为1个2位数字4的数字N(一,二)的映射,其中一个是数字1,两个是数字2,N = 4*1 +两个; 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 >> 2*N)和0x3.表达式(一个<< 3)和(两个<< 1)只是将事物相乘,同时注意到2*x = x << 1和8*x = x << 3.

  • 我认为这是非常糟糕的做法.除了作者之外,没有其他人会理解这一点.您希望查看一段代码并快速理解它.但这只是浪费时间. (106认同)
  • 所有的downvoters都认为这是一种可怕的代码味道.所有的赞成者都这么认为,但要钦佩它背后的聪明才智.+1(不要使用此代码.) (90认同)
  • 聪明,但没有其他人阅读代码将有机会理解它. (79认同)
  • 我和@BalázsMáriaNémeth在一起.虽然非常令人印象深刻,但你应该为暴力精神病患者编码! (14认同)
  • 我无法相信这有很多(或任何)赞成票. (5认同)
  • [只写代码](https://en.wikipedia.org/wiki/Write-only_language)的一个可爱的例子! (4认同)
  • @rdurand或嵌入式系统的实现. (3认同)
  • 我同意这不是我放在企业应用程序中的东西.但是OP并没有问如何将它写成企业,也许他应该.他要求的是做这件事的公式.这个答案给了他那个. (3认同)
  • 这是一个非常优雅的解决方案,但它应该伴随着评论中的答案才能被理解.一点点的方法也是我的第一直觉,很高兴有人这样做.+1因为你赚了它. (3认同)
  • 我认为所有if-else语句都可以作为对此代码的注释. (3认同)
  • Java确实允许将注释包含在源文件中,这一事实否定了许多针对此的论据. (3认同)
  • 你能解释一下吗? (2认同)
  • 我也喜欢这个答案,但我不会将此作为新手程序员的"好提示".第一个目标应该是可读性,只有在你去打高尔夫球之后. (2认同)
  • 这个代码必须进行"表驱动"单元测试,单元测试也将解释代码的作用. (2认同)
  • 适合在汇编中使用C64编程,但是Java ?! (2认同)
  • @waTeim我知道我听起来像一个完整的菜鸟,但你可以解释一下这是如何工作的吗?你是怎么想出这个答案的,是否有一篇文章可以帮助我理解和使用它? (2认同)
  • @MartinSchröder所以你认为Java本质上能够清楚地表达注释功能是语言中的错误吗?就个人而言,我认为能够做上述事情的能力,单凭语言特征无法明确,并在评论中解释,这是一个加号,而不是减号. (2认同)

Eri*_*ert 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);
}    
Run Code Online (Sandbox Code Playgroud)

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

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

  • 废话.大多数经验丰富的程序将能够欣赏这里给出的建议,并将编码风格应用于他们自己的语言.问题是如何避免一串ifs.这说明了如何. (66认同)
  • @ user3414693:我很清楚这是一个Java问题.如果你仔细阅读答案就会变得清晰.如果你认为我的答案是不明智的,那么我鼓励你写下自己喜欢的答案. (6认同)
  • @SList没有,评论不运行.OP完全应该做的事情; 将注释转换为清除代码.参见例如Steve McConnell*代码完成*http://www.stevemcconnell.com/cccntnt.htm (3认同)

djm*_*.im 87

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

int[][] results = {{0, 0, 1, 2}, {0, 0, 2, 1},{2, 1, 3, 3},{2, 1, 3, 3}};
Run Code Online (Sandbox Code Playgroud)

当你想获得价值时,你会使用

public int fightMath(int one, int two) {
  return this.results[one][two]; 
}
Run Code Online (Sandbox Code Playgroud)


JAB*_*JAB 69

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

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
}
Run Code Online (Sandbox Code Playgroud)

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

int[][] results = {{0, 0, 1, 2},
                   {0, 0, 2, 1},
                   {2, 1, 3, 3},
                   {2, 1, 3, 3}};
Run Code Online (Sandbox Code Playgroud)

更新:鉴于你提到阻塞/命中,这里是对函数的一个更彻底的改变,它利用了属性/属性保持枚举类型的输入和结果,并且稍微修改了结果以解决阻塞,这应该导致更多可读功能.

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;
}
Run Code Online (Sandbox Code Playgroud)

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


对于成功的块导致计数器的情况,您可以替换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;
}
Run Code Online (Sandbox Code Playgroud)

此外,if使用三元运算符(boolean_expression ? result_if_true : result_if_false)替换一些语句可以使代码更紧凑(例如,前一个块中的代码将变为return one.isAttack() ? LandedHit.PLAYER_TWO : LandedHit.PLAYER_ONE;),但这可能导致难以读取的oneliner,所以我不会'推荐它用于更复杂的分支.

  • 这是最易读的解决方案,因为它将代码转换为对于阅读代码的人有意义的内容. (7认同)
  • @ TomFirth84有一个[`EnumMap`](http://docs.oracle.com/javase/7/docs/api/java/util/EnumMap.html)类可用于将枚举映射到整数偏移量(你也可以直接使用枚举成员的序数值,例如`Move.ATTACK_HIGH.ordinal()`将是'0`,`Move.ATTACK_LOW.ordinal()`将是'1`等,但是更多脆弱/不灵活,而不是明确地将每个成员与一个值相关联,因为在现有成员之间添加枚举值会导致计数丢失,这与"EnumMap"不同.) (2认同)
  • 你甚至可以在`Move`枚举中添加一个`attack(against)`方法,当移动成功攻击时返回HIT,当移动是阻塞攻击时返回BACKFIRE,当它不是攻击时返回NOTHING.通过这种方式你可以实现它(`public boolean attack(Move other){if this.isAttack()return(other.isAttack()|| other.height!= this.height)?HIT:BACKFIRE; return NOTHING; }),并在需要时在特定的移动上覆盖它(任何块可以阻挡的弱移动,从不回击的攻击等) (2认同)

dj *_*zie 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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

现在也许你已经看到了一些模式,但是当我合并第一和第二的价值时,我看到你正在使用所有值0000,0001,0010,...... 1110和1111.现在让我们结合第一和​​第二的值来制作一个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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

然后是数组{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]; 
Run Code Online (Sandbox Code Playgroud)

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

  • 如今,如果我没有弄错的话,编译器无疑会认识到你乘以2的幂并相应地优化它.所以对你来说,程序员,位移和乘法应该具有完全相同的性能. (6认同)
  • 2的位移几乎肯定比4的乘法更快.最多乘以4,将认识到4是2 ^ 2并且本身做了一点移位(可能由编译器翻译).坦率地说,对我而言,这种转变更具可读性. (2认同)

eli*_*ias 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我同意这个解决方案,看起来很像我在主要问题的评论中的想法.我更愿意将其拆分为单独的变量,这样可以更容易地添加中间攻击,例如将来. (2认同)
  • 我在测试之后修复了上面代码中的一些错误,现在它运行良好.进一步研究比特操纵器的方式我也想出了一个单线解决方案,它仍然不像其他答案中的位掩码一样神秘,但仍然很难搞砸你的想法:`return((one ^ two)& 2)== 0?(1&2)/ 2*3:((1&2)/ 2 ^((1 ^ 2)&1))+ 1;` (2认同)

Joe*_*per 20

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

你可以嵌套ifs,所以你的上一次if检查可能会有轻微的性能提升,因为它不会经历尽可能多的if语句.但是在基本的java课程中,它可能不会受益.

else if(one == 3 && two == 3) { result = 3; }
Run Code Online (Sandbox Code Playgroud)

所以,而不是......

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; }
Run Code Online (Sandbox Code Playgroud)

你做...

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; }
}
Run Code Online (Sandbox Code Playgroud)

然后根据您的喜好重新格式化.

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

  • 不知道这是否真的很好,但对于这种情况,我可能会使用嵌套的switch语句.这将需要更多的空间,但它会非常清楚. (3认同)

Jac*_*ley 12

让我们看看我们所知道的

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

2:3节拍0节拍2节拍1节拍3.这些案例未涵盖的唯一案例是0对1和2对3的组合.换句话说,唯一的胜利表看起来像这样:0节拍2,1节拍3节,2节拍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];
}
Run Code Online (Sandbox Code Playgroud)

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

// 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


Chr*_*ris 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;
}
Run Code Online (Sandbox Code Playgroud)

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

编辑:算法没有完全理解,阻止"击中"时我没有意识到(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;
}
Run Code Online (Sandbox Code Playgroud)


Fra*_*cia 10

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

我会选择一个简单的开关.为此,您需要进行单一数字评估.但是,对于这种情况,因为0 <= one < 4 <= 90 <= two < 4 <= 9,我们可以通过乘以one10并添加将两个int转换为简单的int 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;
}
Run Code Online (Sandbox Code Playgroud)

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

真的只是额外的注释,以防我遗漏了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];
}
Run Code Online (Sandbox Code Playgroud)


Nic*_*kis 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;
}
Run Code Online (Sandbox Code Playgroud)

  • @FDinoff我本可以使用`else`链但是它没有任何区别. (3认同)
  • @BrandonBearden在这里他们不会有任何区别(假设输入始终在0..3范围内).无论如何,编译器可能会对代码进行微优化.如果我们有很长的`else if`语句系列,我们可以用`switch`或查找表来加速代码. (2认同)

Nev*_*r K 6

尝试使用开关外壳...

看看这里这里有关它的更多信息

switch (expression)
{ 
  case constant:
        statements;
        break;
  [ case constant-2:
        statements;
        break;  ] ...
  [ default:
        statements;
        break;  ] ...
}
Run Code Online (Sandbox Code Playgroud)

您可以向其添加多个条件(不同时),甚至可以使用默认选项,其中不满足其他任何情况.

PS:只有满足一个条件..

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

Java switch语句多种情况


Dav*_*ble 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

    //case 22:
    //case 23:
    //case 32:
    //case 33:
    default:
        return 3;
Run Code Online (Sandbox Code Playgroud)

此方法的优点是,与其他一些建议的方法相比,更容易查看哪些值onetwo哪些返回值对应.


Daw*_*ica 6

((two&2)*(1+((one^two)&1))+(one&2)*(2-((one^two)&1)))/2
Run Code Online (Sandbox Code Playgroud)

  • 如果我必须保持这一点,我会非常难过. (7认同)
  • 到达这个时间需要多长时间? (4认同)
  • @mbatchkarov大约10分钟阅读其他答案,然后10分钟用铅笔和纸涂抹. (2认同)