【问题标题】:Best solutions for designing two dimensional world - Game of life设计二维世界的最佳解决方案 - 生活游戏
【发布时间】:2014-04-29 04:06:03
【问题描述】:

我需要创建模拟捕食者-猎物关系的应用程序。我可以使用一些框架(例如repast),但我想知道从头开始编写应用程序。

对我来说最大的问题是用食物来源、捕食者和猎物表示地图的方式。

非常简单的模型

我在考虑二维数组,比如说Cell。 单元格将具有布尔字段 predatorfoodprey 以及相应的设置器和获取器。捕食者和猎物会四处游荡并观察特定半径(视线范围)内的细胞。 如果捕食者发现猎物,它就会向它移动。如果猎物发现捕食者,它会朝相反的方向移动。不受干扰的猎物会四处游荡,直到找到食物来源。

移动/徘徊

在本例中,Animal 前往目的地。

   _ _ _ _ _ _      _ _ _ _ _ _                _ _ _ _ _ _
0 |_|_|_|_|_|_|    |_|_|_|_|_|_|              |_|_|_|_|_|_|
1 |_|A|_|_|_|_|    |_|_|_|_|_|_|              |_|_|_|_|_|_|
2 |_|_|x|x|_|_| -> |_|_|A|x|_|_|    . . .     |_|_|_|_|_|_|
3 |_|_|_|_|x|_|    |_|_|_|_|x|_|              |_|_|_|_|_|_|
4 |_|_|_|_|_|D|    |_|_|_|_|_|D|              |_|_|_|_|_|D|
   0 1 2 3 4 5

此步行需要 5 次移动,动物将有一些特定的速度(2 次移动/秒)。在每一步中,一个 Cell 将predator 设置为false,另一个将其设置为true。 通过编程它看起来像这样(当然会有方法moveTo(x,y)):

Animal animal = new Animal(1,1);
animal.setPosition(2,2);
animal.setPosition(3,2);
animal.setPosition(4,3);
animal.setPosition(5,4);

观察

最大范围为 3 的捕食者观察样本。我已将观察到的细胞标记为 x。观察只是简单地检查getPrey() 是否返回true

   _ _ _ _ _ _ _      _ _ _ _ _ _ _      _ _ _ _ _ _ _          
0 |_|_|_|_|_|_|_|    |_|_|_|_|_|_|_|    |_|_|_|x|_|_|_|      
1 |_|_|_|_|_|_|_|    |_|_|_|x|_|_|_|    |_|x|x|x|x|x|_|        
2 |_|_|_|x|_|_|_|    |_|_|x|x|x|_|_|    |_|x|x|x|x|x|_| 
3 |_|_|x|A|x|_|_| -> |_|x|x|A|x|x|_| -> |x|x|x|A|x|x|x|       
4 |_|_|_|x|_|_|_|    |_|_|x|x|x|_|_|    |_|x|x|x|x|x|_|
5 |_|_|_|_|_|_|_|    |_|_|_|x|_|_|_|    |_|x|x|x|x|x|_|
6 |_|_|_|_|_|_|_|    |_|_|_|_|_|_|_|    |_|_|_|x|_|_|_|
   0 1 2 3 4 5 6

最好的方法是观察每一步(移动)周围的区域,但这似乎需要大量的计算(检查条件)。我在这一点上是正确的吗?

这是将大部分数据保存在二维数组中的好方法吗?我将不胜感激任何建设性的答案。

这只是示例。未来我想添加繁殖、情绪、智能等。

谢谢。

编辑

我忘了提到问题的规模。

我认为 Predators 和 Prey 的数量会少于 100。但这只是猜测。地图大小为 500x500 甚至更小。

【问题讨论】:

标签: java arrays simulation conways-game-of-life


【解决方案1】:

要求最佳解决方案总是意味着令人不舒服的压力。为了正确回答这样的问题并真正给出最佳解决方案,需要在问题规范中提供一定程度的细节,这是康威难以理解的……嗯……在问答网站上传达。

但不仅因为回答这个问题有困难,我建议首先将其建模为一个接口。假设您已经有一个Cell 接口,您可以将 World 表示为

interface World {
    Cell get(int x, int y);
    int getSizeX();
    int getSizeY();
}

根据内存消耗和效率之间的权衡,您可以提供各种实现。对于“密集”(并且非常高效)的实现,您可以使用数组:

class ArrayWorld implements World {
    private Cell cells[][] = ...

    @Override
    public Cell get(int x, int y) {
        return cells[x][y];
    }
    ...
}

对于“稀疏”(虽然效率稍低)实现,您可能会使用类似的东西

class MapWorld implements World {

    // Assuming a class "IntPair" which encapsulates
    // two int values, with proper implementation 
    // of hashCode and equals:
    private Map<IntPair, Cell> map = new HashMap<IntPair, Cell>();

    @Override
    public Cell get(int x, int y) {
        return map.get(new IntPair(x,y));
    }
    ...
}

这里的巧妙之处在于,您可以轻松实现这种元胞自动机中经常使用的世界属性:即,具有“环面”拓扑的世界,其中坐标在边界处“包裹”:

class TorusWorld implements World {
    private World delegate = ...

    @Override
    public Cell get(int x, int y) {
        int wrappedX = ((x % getSizeX()) + getSizeX()) % getSizeX();
        int wrappedY = ((y % getSizeY()) + getSizeY()) % getSizeY();
        return delegate.get(wrappedX, wrappedY);
    }
}

这个“Torus 世界”可以由World 接口的任何其他实现支持。

但是:您还提到了 Animal 类,所以您的 Cell 类应该是什么样子并不完全清楚:Cell 真的包含 Animal 吗?还是只有一组标志显示该单元格是否包含食物、猎物或其他东西? Cell 是否有可能包含 两个 东西(例如,捕食者和食物,它们可能不会相互作用)?这些都是在规范阶段应该尽早回答的问题。

【讨论】:

    【解决方案2】:

    这实际上取决于矩阵的大小以及它的稀疏程度。但是单元模型应该没问题,特别是如果您可以随机访问坐标 (x, y) 并且不想拥有一个巨大的矩阵。对于高效的代码,您可以查看“严肃的”生命游戏实现:

    问题主要在于内存消耗与速度(嗯……像往常一样)。

    您正在寻找的是元胞自动机。 从头开始做这些事情既有趣又有趣。

    【讨论】:

      【解决方案3】:

      您的二维数组方法始终是最容易实现的。 提前考虑最大数组大小。

      如果您需要使用混合了密集和稀疏生命的巨大世界,那么有更好的选择,但它们都更加复杂。

      对于动态二维结构,请查看四叉树,甚至可以将四叉树与二维数组方法混合使用。

      【讨论】:

        猜你喜欢
        • 2018-07-19
        • 2014-12-12
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多