太多'如果'语句?

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

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

为了解释代码,这是一款基于同时回合制的游戏。两个玩家各有四个动作按钮,结果来自一个数组(0-3),但变量“one”&如果有帮助的话,' 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;
}
33838 次浏览

试试开关外壳。..

有关它的更多信息,请查看在这里在这里

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

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

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

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

Java开关语句多例 .

你可以使用一个开关情况来代替多个if

还要提到的是,因为你有两个变量,那么你必须合并这两个变量,以使用它们在开关

检查这个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
}


}

如果你无法想出一个公式,你可以使用一个表格来描述有限的结果:

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

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

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

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

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

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

希望这能有所帮助。

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

您可以嵌套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; }
}

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

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

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

我可能会在某个时候回到这个问题上,但如果没有由多个__abc0语句引起的重大阻力,那么我将暂时保留这个问题。我将进一步研究表格矩阵和开关语句解决方案。

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

其他人已经建议了我最初的想法,矩阵方法,但是除了合并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
}

由于部分输入->结果映射的不规则性,这最终会导致可读性较差。我更喜欢矩阵风格,因为它的简单性和你如何设置矩阵在视觉上有意义(尽管这在一定程度上受到我对Karnaugh地图的记忆的影响):

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,尽管使用__abc0可能比直接等号检查略慢。


对于成功阻塞导致计数器的情况,可以将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;
}
}
或者我是否应该建议将这两比特信息分离成单独的变量? 像上面这样主要基于位操作的代码通常很难维护

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

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

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

由于您的数据集非常小,您可以将所有内容压缩为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) &0 x3。表达式(one <<3)和(两个<<1)只是把它们相乘,同时注意到2*x = x <<1和8*x = x <<3.

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

我会选择一个简单的开关。为此,您需要一个单一的数字求值。然而,对于这种情况,由于0 <= one < 4 <= 90 <= two < 4 <= 9,我们可以通过将one乘以10并添加two来将这两个整数转换为简单的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;
}

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

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

检查一个击中高或一个击中低不被阻止,同样的球员二。

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

看看我们都知道些什么

1:你的答案对于参与人1 P1和参与人2 P2是对称的。这对于格斗游戏来说很有意义,但你也可以利用它来完善你的逻辑。

2:3拍0拍2拍1拍3。这些情况中唯一不包括的情况是0对1和2对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明确的意思是什么的;它们不是任意的值,所以给它们命名会有帮助。

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

我个人喜欢级联三元运算符:

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

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

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

这里是一个相当简洁的版本,类似于疫苗的反应。这使用地图来存储哪个移动战胜其他移动。

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

不包含任何“魔法”数字;)

  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并不擅长表达这类数据类型。

静态int val(int i, int u){ Int q = (i &1) ^ (u &1); 返回(i >>1) & lt; & lt;(1 ^ q))|((u >>1) & lt; & lt;问); 代码}< / > < / p >