代码之家  ›  专栏  ›  技术社区  ›  Matthieu Napoli

生命的游戏:如何让“实体”并行进化?

  •  7
  • Matthieu Napoli  · 技术社区  · 15 年前

    我正在编写某种游戏(如生活游戏)。例如,有 动物 (每个动物都是一个类的Java实例)。

    世界 进化 每次“转身”。

    这些动物可以在每一点上做出动作 . 例子: .

    我环游动物。

    例子:

    • 狼先来 :狼杀了羊(然后羊死了,所以没有行动)
    • 先放羊 :羊吃一些草和草 那么 (狼来了)狼杀了羊

    多线程?(但我会有很多动物,比如1000只甚至更多……)。有没有一个算法,一个“方法”来做到这一点?

    9 回复  |  直到 14 年前
        1
  •  1
  •   Sergey    15 年前

    我认为只有在非常简单的场景中,实体才有可能并行进化(以康威的生活为例)-对于你的“狼-羊-草”世界,你想得越多,它就越复杂:

    • 想想有两只狼和一只羊的情况。狼一决定吃羊;狼二决定吃羊——你怎么决定谁得到羊(假设吃是一个原子操作——狼不能分享它们的食物)。所以你仍然需要决定一些顺序,比如说狼一得到一只羊,狼二什么也得不到(这对狼二来说完全出乎意料——一秒钟前有一只羊,它张开嘴——砰!-什么都没有)

    因此,我认为简单地遍历动物列表,并为每个动物调用一个执行原子操作的方法,就会得到一个更符合逻辑的宇宙。如果你担心早产的动物比晚产的动物有不公平的优势,你可以在每个回合前随机列出动物的名单——这样,在你的例子中,要么羊吃了一些草然后被狼吃掉,要么狼在有机会吃任何草之前吃掉了它。这就是生活。

        2
  •  10
  •   Péter Török    15 年前

    每一个 动物根据 世界的状态,使行动的结果得到更新

    1. 在当前步骤中,羊吃了一些草,狼就把它杀死了。

    这样,评估的顺序就不会影响结果,这就为并行执行提供了可能性,最好使用 FutureTask s和a ThreadPoolExecutor .

        3
  •  4
  •   Eyal Schneider    15 年前

    线程并发性不是这里的主要问题。我认为正确的模式应该是允许每个实体在当前回合中决定一项行动。然后,为了在下一回合确定游戏状态,你应该处理动作,如果需要的话解决冲突。你应该决定规则来解决两个不同的玩家所采取的各种“冲突”的动作组合。

        4
  •  3
  •   Rodney Gitzel    15 年前

    哦,你不想进入多线程,事情会变得更加混乱。

    在这种情况下,遍历所有动物,让它们选择自己的动作。然后更新地图。

        5
  •  1
  •   Escualo    15 年前

    如果您有一个可以接收和发出通知的中央管理器,那么您可以使用 Observer pattern . 每次转弯时,动物都会通知自己在哪里。经理通知谁在那里,然后他们执行任务 eat() notify() 经理,然后告诉他们该做什么(例如。 sheep.die() )

        6
  •  1
  •   Jason Goemaat    15 年前

    听起来你希望世界每一次都像康威的生活一样以同样的方式进化。在生活中,你观察每一个细胞,计算出它的结果是基于 州。如果这个细胞有两个邻居,它将活到下一代,不管这些邻居在下一代是否不在那里。原始状态应该是只读的,不管发生什么,规则都应该起作用。

    例如,如果你有两只狼靠近一只羊,它们会都吃,还是只有一只?如果只有一个,那么你需要一个规则,一个吃羊,另一个需要知道这一点。你可以走相反的路,也就是说,看看羊,找到一只会吃它的动物。假设你只想让一只狼吃掉羊,你说Y坐标最低的狼得到羊,如果有两只Y坐标相同的狼,那么X坐标最低。如果你正在处理一只狼,你需要确保没有其他狼会先吃掉羊。这可能会让人更加困惑,因为可能附近还有另一只羊,它会吃,所以它不会吃第一只羊。。。

    最简单的方法是说所有的动物都可以做他们的行为,不管在下一轮进化中发生了什么,或者其他动物做了什么。如果一只羊被三只狼包围,它将在下一轮死亡,所有的狼将分享这顿饭。如果羊旁边有草,即使羊被狼围着,羊也会吃。对狼来说,那一轮都要喂它们,因为它们挨着一只羊。

    public class Cell {
        public int CellType = 0; // 0 == empty, 1 == grass, 2 == sheep, 3 == wolf
        public int Feedings = 0;
    }
    
    public class World {
    public Cell [] Cells = new Cell[100];
    public int Rows = 10, Cols = 10;
    
    public Cell GetCell(x, y) {
        if (x < 0 || x >= Cols || y < 0 || y >= Rows) return null;
        if (Cells[y * Cols + x] == null) {
            Cells[y * Cols + x] = new Cell();
        }
        return Cells[y * Cols + x];
    }
    
    public World Evolve() {
        World w = new World();
        for (int y = 0; y < Rows; y++) {
            for (int x = 0; x < Cols; x++) {
                HandleCell(w, x, y);
            }
        }
        return w;
    }
    
    public void HandleCell(World newWorld, int x, int y) {
        Cell result = newWorld.GetCell(x, y);
    
        Cell c = GetCell(x, y);
        if (c.CellType == 2) { // sheep
            bool foundWolf = false;
            bool foundGrass = false;
    
            // code here to find if a wolf or grass are around the sheep
    
            if (foundWolf) {
                // default cell type is empty, so leave it be (wolf ate me)
            } else {
                result.cellType = 2; // still a sheep here
                if (foundGrass) {
                    result.Feedings = c.Feedings + 1; // and he ate!
                } else {
                    result.Feedings = c.Feedings; // or not...
                }
            }
        }
    
        if (c.CellType == 3) { // wolf
            bool foundSheep = false;
    
            // code here to find if a sheep is around the wolf
    
            result.CellType = 3;
            if (foundSheep) {
                result.Feedings = c.Feedings + 1; // ate the sheep!
            } else {
                result.Feedings = c.Feedings;
            }
        }
    }
    
        7
  •  0
  •   Javid Jamae    15 年前

    在我脑子里,你可能会这样做:

    玩家

    • 公共空间转换(世界)

    当世界实例到达每个玩家时,它会询问它是否已死亡。如果不是,则调用takeTurn方法。或者,takeTurn可以在内部调用isDead(),如果是就返回。如果你杀死了另一个玩家(或者你自己),你只需要调用玩家的杀死方法。

    将世界传递给takeTurn只是为了防止您需要回调以更新 世界现状 .

        8
  •  0
  •   mikek3332002    15 年前

    一种方法是:

    1. 让羊做下一步的动作并记录下来。
    2. 更新牧羊人行动的公告板
    3. 做每一个狼的行动,并记录在下一步。
    4. 更新wolf操作板。

    两种方式两个多线程这是:

    • 另一种方法可能是将生物循环到不同的线程。如

      for(w=THREAD_NUM; w<NUM_OF_WOLVES; w+=NUM_OF_THREADS) { w.doAction(); }

        9
  •  0
  •   sventevit    15 年前

    也许你可以随意做。

    第一个随机示例:羊吃草,然后狼吃羊(羊->狼)

    第二个随机的例子:狼吃羊,因为这个可怜的家伙太慢了,走不到草地上(狼->/)

    现实世界是确定性的吗?:)

    推荐文章