我有下面的类,移动人工智能到给定的工厂,这是很好的工作,但它感觉真的很混乱。
任何关于更好地布局逻辑的输入都将是非常感激的,逻辑遵循这样的思想:我们将从植物位置获取人工智能的x和y位置,如果值为正,则添加30,如果值为负值,则取掉30。
如果你还需要解释逻辑的话,请告诉我。
private void movePosistion(Plant p) {
/*
* set which direction to move,the number generated relates to the
* direction as below:
* 1 2 3
* 4 5
* 6 7 8
*/
int xdiff = p.getXpos() - xpos;
int ydiff = p.getYpos() - ypos;
if (xdiff > 0){
if (ydiff > 0){
//8
xpos += 30;
ypos += 30;
}else if(ydiff < 0){
//3
xpos += 30;
ypos -= 30;
}else{
//5
xpos += 30;
}
}else if(xdiff < 0){
if (xdiff > 0){
//6
xpos -= 30;
ypos += 30;
}else if(xdiff < 0){
//1
xpos -= 30;
ypos -= 30;
}else{
//4
xpos -= 30;
}
}else{
if (ydiff < 0){
//7
ypos -= 30;
}else{
//2
ypos += 30;
}
}
if (xpos > 720)
xpos = 1;
if (ypos > 720)
ypos = 1;
if (xpos < 1)
xpos = 720;
if (ypos < 1)
ypos = 720;
}
发布于 2014-04-10 20:54:13
以下是我的重构:
private void movePosition(Plant p) {
xpos += Integer.signum(p.getXpos() - xpos) * DELTA_X;
ypos += Integer.signum(p.getYpos() - ypos) * DELTA_Y;
xpos = Math.floorMod(xpos, MAX_X);
ypos = Math.floorMod(ypos, MAX_Y);
}
使用正确的import static
,也可以是:
private void movePosition(Plant p) {
xpos = floorMod(xpos + signum(p.getXpos() - xpos) * DELTA_X, MAX_X);
ypos = floorMod(ypos + signum(p.getYpos() - ypos) * DELTA_Y, MAX_Y);
}
signum
实现符号函数,它分别为负整数、零整数和正整数提供-1、0或1。它用一个非常简短和可读的表达式对原始逻辑进行编码。符号乘以适当数量的单位(常量在代码中没有详细说明,顺便说一句)。原则上,我不反对决策表(见rolfl的回答),但我认为这里没有必要这样做。在他的回答中,palacsint引用了“代码完整”。我也能做到!
代码完整第二版,第19章:一般控制问题,第431页:
使用决策表来替换复杂的条件,有时需要进行涉及多个变量的复杂测试。...
..。有时候你不知道;-)
通过模数运算可以实现原码的包绕行为.请注意,您不能只在Java中使用%
运算符,因为它计算余数,当位置低于零时,余数可能为负数。floorMod
操作实际上是计算模块化算法。
现在,你可能会想:这是错误的,原来的代码不是这样工作的!是的,但让我解释一下:
x
是710,然后加上30:对于模,我返回到20,而使用OP的代码,我会得到1,因为当我们超出界限时,我们返回到最小(或最大)位置。对此,我的答复是,你从来没有在第710位,但只在0,30,60,…,690。至少,这是我从OP的代码中了解到的,在该代码中,对象似乎在网格上移动,而不是随意地移动。我想物体最初的位置总是在30的倍数上,然后只能移动30个单位。如果我错了,那么(1)对不起,(2)是的,模数不是很好的答案;您最好使用rolfl中的boundPos
函数。发布于 2014-04-10 18:44:50
预先计算可能的移动,并将条件简化为一个简单的数学表达式是解决此类问题的好方法。
您的代码还会受到重复块和重复逻辑的影响:干-不要重复自己。
通过函数提取来解决这一问题。
最后,您的代码充满了神奇的数字,这些数字很容易泄漏错误……
考虑下面的代码,虽然在行方面比您的代码更长,但实际上可读性要高得多(我承认,除了复杂的2D数组之外)。
private static final int DELTA = 30;
private static final int MINPOS = 0;
private static final int MAXPOS = 720;
private static final int XINDEX = 0;
private static final int YINDEX = 1;
private final int[][] MOVES = {
{-DELTA, DELTA}, {0, DELTA}, {DELTA,DELTA},
{-DELTA, 0}, {0, 0}, {DELTA,0},
{-DELTA, -DELTA},{0, -DELTA},{DELTA,-DELTA},
};
private final int step(final int diff) {
return diff < 0 ? 0 : (diff > 0 ? 2 : 1);
}
private final int boundPos(int pos) {
return pos < MINPOS ? MAXPOS : (pos > MAXPOS ? MINPOS : pos);
}
private void movePosistion(Plant p) {
/*
* set which direction to move,the number generated relates to the
* direction as below:
* 1 2 3
* 4 5
* 6 7 8
*/
int xdiff = step(p.getXpos() - xpos);
int ydiff = step(p.getYpos() - ypos);
// Convert the two x/y directions to an index in to MOVES.
int index = ydiff * 3 + xdiff;
xpos += MOVES[index][XINDEX];
ypos += MOVES[index][YINDEX];
xpos = boundPos(xpos);
ypos = boundPos(ypos);
}
发布于 2014-04-10 19:17:07
我同意@rolfl,您需要提取方法并使用决策表。
代码完整第二版,第19章:一般控制问题,第431页:
使用决策表来替换复杂的条件,有时需要进行涉及多个变量的复杂测试。使用决策表执行测试可能会有帮助,而不是使用ifs或case。决策表查找一开始更容易编码,只有几行代码,没有复杂的控制结构。这种复杂性的最小化减少了出错的机会。如果数据发生更改,则可以更改决策表而不更改代码;只需更新数据结构的内容即可。
为了可读性,我在这里会更详细。首先,对可能存在的差异作一说明:
public enum Difference {
ZERO,
BELOW_ZERO,
ABOVE_ZERO
}
然后是包含可用规则的类:
public class MoveLogic {
private final Map<Rule, Move> rules = new LinkedHashMap<>();
public MoveLogic() {
addRule(Difference.ABOVE_ZERO, Difference.ABOVE_ZERO, 30, 30); // 8
addRule(Difference.ABOVE_ZERO, Difference.BELOW_ZERO, 30, -30); // 3
addRule(Difference.ABOVE_ZERO, Difference.ZERO, 30, 0); // 5
addRule(Difference.BELOW_ZERO, Difference.ABOVE_ZERO, -30, 30); // 6
addRule(Difference.BELOW_ZERO, Difference.BELOW_ZERO, -30, -30); // 1
addRule(Difference.BELOW_ZERO, Difference.ZERO, -30, 0); // 4
addRule(Difference.ZERO, Difference.BELOW_ZERO, 0, -30); // 7
addRule(Difference.ZERO, Difference.ABOVE_ZERO, 0, 30); // 2
}
private void addRule(Difference xDifference, Difference yDifference, int x, int y) {
rules.put(new Rule(xDifference, yDifference), new Move(x, y));
}
public Move getMove(Difference xDifference, Difference yDifference) {
return rules.get(new Rule(xDifference, yDifference));
}
}
用法:
final Difference xDifference = calculateDifference(plant.getXpos(), xpos);
final Difference yDifference = calculateDifference(plant.getXpos(), ypos);
final Move move = moveLogic.getMove(xDifference, yDifference);
xpos += move.getX();
ypos += move.getY();
最后,创建Difference
引用的助手方法:
private Difference calculateDifference(final int plantPosition, final int position) {
final int difference = plantPosition - position;
if (difference > 0) {
return Difference.ABOVE_ZERO;
}
if (difference < 0) {
return Difference.BELOW_ZERO;
}
return Difference.ZERO;
}
以及Rule
:
public class Rule {
private Difference xDifference;
private Difference yDifference;
public Rule(Difference xDifference, Difference yDifference) {
this.xDifference = xDifference;
this.yDifference = yDifference;
}
// generate hashCode and equals, the Map needs it!
}
和Move
:
public class Move {
private int x;
private int y;
public Move(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
它可能看起来过于冗长,但它避免重复的条件,以及神奇的计算与索引和数组。
https://codereview.stackexchange.com/questions/46834
复制相似问题