我是Java的新手,并且此代码可能会压缩成一堆。如何使此代码更简单易读?

chance.base是百分比。如果它等于40,则有40%的机会返回true

public class battleManager {

void battle(Army playerArmy,Army enemyArmy,int armyModifier,int army2Modifier){

    if(armyModifier > 40| army2Modifier > 40){
        System.out.println("note: modifiers were over maximum (40)");
    }
    chanceManager chance = new chanceManager();
    chance.base = (50 + armyModifier) - army2Modifier;
    int armyCount = playerArmy.units, army2Count = enemyArmy.units;
    boolean armyAlive = true, army2Alive = true, playerWon = false;

    while(armyAlive & army2Alive){

        if(chance.generate()){
            army2Count--;
        }
        else{
            armyCount--;
        }

        if(armyCount == 0){
            armyAlive = false;
            playerWon = false;
        }

        if(army2Count == 0){
            army2Alive = false;
            playerWon = true;
        }
    }
    chance.base = 25;
    int armyKilled, army2Killed;
    armyKilled = playerArmy.units - armyCount;
    army2Killed = enemyArmy.units - army2Count;

    for (int unit = 0; unit < armyKilled; unit++){
        if(chance.generate()){
            armyCount++;
        }
    }

    for (int unit = 0; unit < army2Killed; unit++){
        if(chance.generate()){
            army2Count++;
        }
    }

    // this is for debugging
    System.out.println("army survivors:");
    System.out.println(armyCount);
    System.out.println("army2 survivors:");
    System.out.println(army2Count);

    if(playerWon){
        System.out.println("player army won");
    }else
        System.out.println("Player army lost");
    // end of debugging

    playerArmy.units = armyCount;
}


评论

40、50和25是en.wikipedia.org/wiki/Magic_number_%28programming%29。避免它们

#1 楼

命名

类名称应按惯例以UpperCase字母开头。

什么是battleManager?什么是choiceManager?为什么不ColonelSandersVicePresidentOfChoice?除了开玩笑,命名可能更具描述性。 BattleSimulatorBernoulliTrial怎么样?

参数的命名不一致:


battle(Army playerArmy,Army enemyArmy,int armyModifier,int army2Modifier)



其中任何一个更加合乎逻辑:

battle(Army playerArmy, Army enemyArmy, int playerModifier, int enemyModifier)
battle(Army army1, Army army2, int army1Modifier, int army2Modifier)
battle(Army attacker, Army defender, int attackerModifier, int defenderModifier)


如果模拟的局势是非对称的(例如,攻击者的军队正试图进入防御者的领土),则最后一种选择将特别有吸引力。 )。通常,规则将要求攻击者至少拥有n个单位,而防御者可能根本没有单位。 (在battle方法的开始声明以强制执行这样的规则也是个好主意。)

面向对象设计

battle方法应为public

函数返回战斗胜利者会很有用。

不建议设置chance.base来修改概率,因为您允许其他人介入chance对象的内部。三种更好的方法是:


BernoulliTrial battleProb = new BernoulliTrial(50 + army1Modifier - army2Modifier);
battleProb.setProbability(50 + army1Modifier - army2Modifier);
battleProb.generate(50 + army1Modifier - army2Modifier);

请参阅以下有关更具创意的命名建议-我认为它读得更多

算法

有一个战斗阶段和一个康复阶段。

康复之后,您可以恢复playerArmy的一些伤亡。但是,您对敌人的军队也不会这样做。要么是疏忽,要么是治愈循环之一。我以为只有获胜的军队应该得到医治。

您可以直接在循环内操纵军队的单位数,而不是在循环后设置单位数。

最好不要使用armyAlivearmy2Alive标志。

assert(attacker.units > 0);

BernoulliTrial attack = new BernoulliTrial(50 + attackerModifier - defenderModifier);
int attackerCasualties = 0, defenderCasualties = 0;

// Begin fighting
while (attacker.units > 0 && defender.units > 0) {
    if (attack.success()) {
        defender.units--;
        defenderCasualties++;
    } else {
        attacker.units--;
        attackerCasualties++;
    }
}
Army winner = (attacker.units > 0) ? attacker : defender;

// Heal the winning army
BernoulliTrial heal = new BernoulliTrial(25);
int winnerCasualties = (winner == attacker) ? attackerCasualties : defenderCasualties;
while (winnerCasualties-- > 0) { 
    if (heal.success()) {
        winner.units++;
    }
}

return winner;


评论


\ $ \ begingroup \ $
for循环内的三进制不是很可读。 :p
\ $ \ endgroup \ $
–RobAu
2014年12月10日在9:11

\ $ \ begingroup \ $
没有使用int units变量,并且由于winner.units,它的名称令人困惑。而且我看不出递减的意义。我会做inturingCandidates =(三元); while(healingCandidates--> 0){...}。我也不喜欢有2个三元组。
\ $ \ endgroup \ $
– njzk2
2014年12月10日20:19

\ $ \ begingroup \ $
@RobAu按大众需求重写了循环(第5版)。
\ $ \ endgroup \ $
– 200_success
2014年12月10日20:22

#2 楼


命名不一致。任一部队应为army1, army2或相关变量应为playerArmyAlive, enemyArmyAlive等。

对称性被破坏。可以合理地预期在方法末尾有enemyArmy.units = army2Count(否则为什么还要计算army2Count?)。

更多关于对称性。如果确实要复活两军,请在方法中考虑到这一点

void resurrect(Army army, int killed) {
    while (killed-- > 0) {
        if (chance.generate()) {
            army.units++;
        }
    }
}


为每场战斗实例化chance看起来并不正确。感觉像是battleManager的成员。魔术常数4025也是一样。
armyAlive是多余的;它是armyCount == 0谓词的同义词,确实感觉像Army方法。


#3 楼

我发现我们可以为您提供很多帮助。

操作员。

您使用:

while(armyAlive & army2Alive)


您可以将其重写为:

while(armyAlive && army2Alive).


简短说明:如果first为false,则不会检查语句2。在此情况下,始终检查两个操作数的情况。此处长说明。

使用正确的方法

名称可能很奇怪,但我想说的是,您在经理中。
您想在2之间进行战斗陆军的。
为什么不返回军队赢了什么呢?
当你逻辑地思考时,战斗只需要发生,就需要知道谁赢了。

设置在正确的地方放置正确的东西。

如果是我,我将在Army类中实现isAlive方法,例如:

public boolean isAlive () {
    return units > 0;
}

public void loseAUnit() {
    units--;
}


然后将代码更改为:

int playerStartUnits = playerArmy.units, enemyStartUnits = enemyArmy.units;
while(playerArmy.isAlive() && enemyArmy.isAlive()){
    if(chance.generate()){
        enemyArmy.loseAUnit();
    }
    else{
        playerArmy.loseAUnit();
    }
}
Army winner = playerArmy.isAlive()?playerArmy:enemyArmy;

resurrect(playerArmy,playerStartUnits,chance);
resurrect(enemyArmy,playerStartUnits,chance);

return winner;


对于重新生成,@ vnp已经提到了如何实现,只是他没有提到您必须发送

我只是觉得很奇怪,你只让玩家回到他的单位,而不是让敌人在复活后回到他的部队。
我的意思是你还可以使敌军复活,但永远不要让他们退缩。
或者您删除敌军的复活,或者确实让他们退缩。

#4 楼

我可以理解的一些方法:使用按位运算符(|&)代替逻辑运算符(||&&)。尽管它是正确的,但是请确保您不要误用它。
boolean ArmyAlive,可以避免Army2Alive。而是使用count。

将System.out.println-s合并为一行(如果有的话)。

System.out.println("army survivors: " + armyCount);


使用DEBUG标志包含日志,以便在调试和其他方式之间轻松切换。

更新参数不是很好。假设它们是最终的。而是返回需要更新的内容。 (邀请/反对意见相同)。

playerArmy.units = armyCount;



playerWon可以在while循环外进行如下计算:

while(armyAlive & army2Alive){
    if(chance.generate()){
        army2Count--;
    }
    else{
        armyCount--;
    }
}
playerWon = (army2Count == 0);`


如果假设playerArmy或敌人Army为空,请进行验证检查。
一个严重的错误:如果armyCountarmy2Count<=0,则要过一段时间才能知道。 br />您想知道哪个修饰语是>40。如果是,请将其添加到日志中。


#5 楼

void battle(Army playerArmy, Army enemyArmy, int armyModifier, int army2Modifier){


尝试避免并行数据结构。它们使系统更加脆弱,因为您必须维护关系。如果需要并行结构,请尝试使名称保持一致。在这里您似乎同时将其称为enemyArmyarmy2

为什么不在modifier中创建一个Army字段?这样就可以确保将正确的modifier与正确的Army相关联。

考虑将modifier重命名为strengthbattlePower之类的名称,以便更清楚地了解其功能。您可能正在修改几乎所有内容。几乎没有比number好。

此外,任何时候只要发现自己为变量命名为一和二时,就有很大的机会应该使用Collection。在这种情况下,可能是List

if(armyModifier > 40| army2Modifier > 40){
while(armyAlive & army2Alive){


您正在使用|&。您应该使用仅逻辑运算符(||&&)。如果后者可以从第一个操作数确定表达式值,则它们短路并且不处理第二个操作数。您几乎应该始终使用它们。这在这里并不重要,因为第二个表达式非常简单。但是在某些情况下,使用短路操作器可以提高性能。

if ( armyModifier > 40 || army2Modifier > 40 ) {
while ( armyAlive && army2Alive ) {


即使在这里,性能也会有所改善。

    if(armyCount == 0){


这种检查有风险。如果您改变战斗方式而有双重伤害几率\\ 1 \%\ $,会发生什么情况?然后,您的armyCount可能会直接从\ $ 1 \ $转到\ $-1 \ $。您的军队可能会以负兵获胜,因为一旦变为负兵就无法达到\ $ 0 \ $。如果两军都发生这种情况,则可以继续操作,直到超出整数范围。

    if ( armyCount <= 0 ) {


面对代码更改,这样做更安全,更可靠。它将遇到直接平等检查将丢失的情况。

// this is for debugging
System.out.println("army survivors:");
System.out.println(armyCount);
System.out.println("army2 survivors:");
System.out.println(army2Count);

if(playerWon){
    System.out.println("player army won");
}else
    System.out.println("Player army lost");
// end of debugging


如果要将代码发送出去进行审核,则不应使用这种调试代码。在您获得评论时,您应该已经删除了它。考虑编写单元测试来处理这种调试。这样,当您真正运行它时,就不会使您的代码混乱。

我会考虑将您的某些逻辑移至Army类。例如,您可以将armyAlive变量替换为方法调用:playerArmy.isActive()。您可以将armyCount的手动减量替换为playerArmy.takeCasualty()playerArmy.takeCasualties(1)。以后您可以使用playerArmy.healCasualties()方法。

这样做不仅简化了battle,而且减少了重复代码。假设您以名为Listarmies传递军队,您可以说:

for ( Army army : armies ) {
    army.healCasualties(chance);
}


现在您不再关心有多少军队在战斗。您不必为每个循环添加一个新循环。您只需要为每个调用适当的方法,该循环将处理“每个”部分。现在,如果您更改了治疗逻辑,则可以为两军更改它,而不必并行修改两段代码。

您甚至可能没有将armies传递给battle函数。如果您有一个battleManager的构造函数,则可以传递armies之类的东西,然后治愈百分比。可能battle没有参数。

或者,如果要保持事物的现状,则应将battle设为static方法。对于不依赖于任何类字段的方法,这更有意义。

public static void battle(List<Army> armies) {


这假设您也将修饰符移到了Army中。

评论


\ $ \ begingroup \ $
修饰语可能不是各自军队的属性。也许它们是银行里有多少钱,公民的士气或技术进步的函数。
\ $ \ endgroup \ $
– 200_success
2014-12-10 7:21