我正在为一个游戏编写人工智能对象。
我的目标是对代码进行优化,以便能够同时处理尽可能多的AI进程。
游戏是2d物理,所以我已经处理实体数字瓶缩在碰撞处理,所以人工智能将需要有效率。
我处理的命令是简单的ASDF + QE移动,鼠标点击和位置。
我意识到,在实际的键/鼠标上模拟AI动作可能不是什么好主意。但我想先从这里开始,然后再把它拆开。
我决定使用布尔数组表示命令,如下所示:
//Commands: continue, up, down, left, right, turnQ, turnE, mouse0, mouse1
boolean[] moveBools = {false, false, false, false, false, false, false, false, false};
//The first boolean in the array 'continue' will terminate the loop if its true.我在苦苦挣扎的是如何将这些数据传递到我的函数中,从而真正地移动物理体。我可以简单地在每个游戏迭代中传递一个完整的布尔数组,或者传递/更改/从一个迭代到另一个迭代。
这种类型的编程连接到实际的布尔数学,这是我所不知道的。我的理论是,我实际上可以创建操作符,就像在C++中所做的那样,让数组状态互相减去,然后输出结果。
问题是:在前面的上下文中,如何以最佳速度传递布尔数组?
发布于 2015-11-03 16:53:27
您所编写的内容的直接转换是使用BitSet。它允许您获得比特的交集/或和andNot。你可以:
BitSet move = new BitSet(9);
move.set(1); // going up
move.set(2); // also going down?您可以通过流toByteArray()并在接收端使用new BitSet(inputByteArray)重新构建这个相对打包的(EG通过网络)。
在一个有效的状态表达式中,这些布尔人中有多少会或应该被设置为真?
如果我们猜到的话,我们可以做一些简单的事情。例如,当继续为真时,所有其他值都被忽略,(对我来说)上下或左、右都是真,这是没有意义的。虽然这可能是有意义的,让其中一个或两个鼠标按钮与其他状态,并有类似的东西,如向上,左和turnQ在同一时间,问题可以简化,如果我们只允许一种状态。
也就是说,如果您表示的是状态,我将定义状态的枚举,并考虑这样做,有效地传递等效为单个数字的bool数组,即枚举的基数。
public enum SingleAiMoves {
NONE, STOP,
LEFT, RIGHT,
UP, DOWN,
TURN_Q, TURN_E,
MOUSE1, MOUSE2
}一次只允许一个州。
如果需要组合多个状态,但只组合有效状态,则可以定义一个逻辑状态组,如下所示:
public enum AiMove {
// u/d l/r q/e m1 m2 stop
STOP (null, null, null, false, false, true),
NONE (null, null, null, false, false, false),
UP (true, null, null, false, false, false),
DOWN (false, null, null, false, false, false),
LEFT (null, true, null, false, false, false),
RIGHT (null, false, null, false, false, false),
TURN_Q (null, null, true, false, false, false),
TURN_E (null, null, false, false, false, false),
MOUSE_1 (null, null, null, true, false, false),
MOUSE_2 (null, null, null, false, true, false),
MOUSE_1_2 (null, null, null, true, true, false),
UP_LEFT (true, true, null, false, false, false),
DOWN_LEFT (false, true, null, false, false, false),
... // some 108(?) combinations listed here.... ;
private final Boolean upDown;
private final Boolean leftRight;
private final Boolean turnQE;
private final boolean mouse1;
private final boolean mouse2;
private final boolean stop;
AiMove(Boolean upDown, Boolean leftRight, Boolean turnQE,
boolean mouse1, boolean mouse2, boolean stop) {
this.upDown = upDown;
this.leftRight = leftRight;
this.turnQE = turnQE;
this.mouse1 = mouse1;
this.mouse2 = mouse2;
this.stop = stop;
}
public boolean isStopped() { return stop; }
public boolean hasUp() { return Boolean.TRUE.equals(upDown); }
public boolean hasDown() { return Boolean.FALSE.equals(upDown); }
public boolean hasLeft() { return Boolean.TRUE.equals(leftRight); }
public boolean hasRight() { return Boolean.FALSE.equals(leftRight); }
public boolean hasTurnQ() { return Boolean.TRUE.equals(turnQE); }
public boolean hasTurnE() { return Boolean.FALSE.equals(turnQE); }
public boolean hasMouse1() { return mouse1; }
public boolean hasMouse2() { return mouse2; }
}就我个人而言,我认为如果您走这条路线,您可能会考虑表示比某些内部控制器输入更详细的状态。
另外,你也可以使用位标志或掩码,或者更干净的、非花哨的EnumSet<SingleAiMoves>,但与上面的枚举不同,就像你的数组和BitSet一样,它允许状态向上和向下,和/或左和右都存在。
最后,由于在上面的示例中,我发现编写假定有效的组合的枚举很乏味,而且相对不可读,所以您可以在枚举中使用BitSet,并澄清枚举的构造。这样可能会占用更多的内存。
public enum AiMove {
NONE (),
UP (0),
DOWN (1),
LEFT (2),
RIGHT (3),
TURN_Q (4),
TURN_E (5),
MOUSE_1 (6),
MOUSE_2 (7),
STOP (8),
MOUSE_1_2 (MOUSE_1, MOUSE_2),
UP_LEFT (UP, LEFT),
DOWN_LEFT (DOWN, LEFT),
... // some 108(?) combinations listed here.... ;
private final BitSet bitsUDLRQE12S = new BitSet(9);
AiMove(int index) {
bitsUDLRQE12S.set(index);
}
AiMove(AiMove... moves) {
for (AiMove move : moves) {
bitsUDLRQE12S.or(move.getBitSet());
}
}
private BitSet getBitSet() { return bitsUDLRQE12S; }
public boolean hasUp() { return bitsUDLRQE12S.get(0); }
public boolean hasDown() { return bitsUDLRQE12S.get(1); }
public boolean hasLeft() { return bitsUDLRQE12S.get(2); }
public boolean hasRight() { return bitsUDLRQE12S.get(3); }
public boolean hasTurnQ() { return bitsUDLRQE12S.get(4); }
public boolean hasTurnE() { return bitsUDLRQE12S.get(5); }
public boolean hasMouse1() { return bitsUDLRQE12S.get(6); }
public boolean hasMouse2() { return bitsUDLRQE12S.get(7); }
public boolean isStopped() { return bitsUDLRQE12S.get(8); }
}发布于 2015-11-03 16:23:29
enum Command {
continuing, up, down, left, right, turnQ, turnE, mouse0, mouse
}
void process(EnumSet<Command> commands) {
while (commands.isEmpty()) {
...
}
...
}恩姆是有可能的。EnumSet是像BitSet这样的最优的东西,EnumMap是一个数组。
否则,使用位掩码并传递一个int。int上的位操作简单,效率略高。
发布于 2015-11-03 16:34:43
Java通过值传递,但在数组的情况下,它通过值传递对数组的引用--单个元素不被传递,只有对数组的初始引用。
这意味着在传递布尔数组时,不是传递所有数组,而是传递引用数组的值。为了清晰和快速,这可能是你最好的选择。
如果您试图优化,不是在速度上,而是在内存方面,那么您可能需要考虑使用java.util.BitSet。
https://stackoverflow.com/questions/33503955
复制相似问题