7

好吧,标题不清楚,这就是我的意思。

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

所有这些动物都在一张地图上,所有这个“世界在每“转”一次。

这些动物每回合都能做出动作。例子:狼杀羊

但是,我对在状态之间进行这些进化的“方式”有疑问,因为结果将取决于我在动物中循环的顺序。

例子 :

  • 狼先:狼杀羊(羊死了,所以没有动作)
  • 羊先:羊吃了一些草,然后(狼的转身)狼杀了羊

我怎么解决这个问题 ?

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

谢谢

4

9 回答 9

10

您应该正确地模拟转弯,即让每只动物根据世界的当前状态轮流,以便动作的结果更新到世界的下一个状态,而不是当前状态。IE

  1. 在当前步骤中,羊吃草,狼将其杀死。
  2. 在世界的下一个状态中,有内容的狼,没有羊(或羊尸体 - 取决于您的模型)。

这样,评估的顺序不会影响结果,这开辟了例如并行执行的可能性,最好使用FutureTasks 和 a ThreadPoolExecutor

于 2010-09-14T22:50:01.303 回答
4

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

于 2010-09-14T23:05:23.660 回答
3

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

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

于 2010-09-14T22:52:46.373 回答
1

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

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

  • 有两只狼和两只羊;两只羊的“吸引力”对两只狼来说都是一样的,所以它们随机选择猎物。不幸的是,他们选择了同一只羊,狼一吃羊一,狼二也想吃羊一,但它神奇地消失在它的鼻子下。回合结束。下一回合,羊二跑了,狼二饿了——这完全不合逻辑。

所以我认为简单地遍历动物列表并为每个执行原子动作的动物调用一个方法会产生一个更合乎逻辑的宇宙。如果您担心较早产生的动物比后来产生的动物具有不公平的优势,您可以在每回合之前随机化动物列表 - 这样,在您的示例中,要么绵羊吃了一些草,然后被狼吃掉,或者狼在它有机会吃任何草之前就把它吃掉了。这就是生活。

于 2010-09-15T01:27:34.940 回答
1

如果你有一个可以接收和发出通知的中央管理器,你可以使用观察者模式。每次转弯时,动物都会通知它们所在的位置。经理通知谁在那里,他们eat()根据上下文执行他们的方法。当他们吃完饭后,他们notify()是经理,他们反过来告诉他们该做什么(例如sheep.die()

于 2010-09-14T22:58:04.877 回答
1

听起来你希望世界每次都像康威的生活一样以同样的方式发展。在 Life 中,您查看每个单元格并根据之前的状态计算它的结果。如果细胞有两个邻居,它就会活到下一代,不管这些邻居在下一代是否会存在。原始状态应该是只读的,无论如何规则都应该起作用。

例如,如果你有两只狼靠近一只羊,它们会同时吃掉它,还是只吃一只呢?如果只有一个,那么您需要一个规则,其中一个可以吃羊,另一个需要知道这一点。你可以走相反的路,即看羊,找一只会吃它的动物。假设您只想让一只狼吃羊,并且您说具有最低“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;
        }
    }
}
于 2010-09-15T00:25:29.580 回答
0

也许你可以完全随机地做到这一点。

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

第二个随机例子:狼吃羊,因为可怜的东西太慢了,来不及草地(狼 -> /)

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

于 2010-09-15T15:32:23.493 回答
0

在我的脑海中,你可能会做这样的事情:

拥有一个管理 Player 对象列表的 World 对象。播放器有以下方法:

播放器

  • public void takeTurn( 世界世界 )
  • 公共布尔 isDead()
  • 公共无效杀死()

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

将 world 传递给 takeTurn 以防万一您需要进行回调以更新world 的状态

于 2010-09-14T23:07:39.037 回答
0

一种方法是:

  1. 让羊做他们的动作,并在下一步记录下来。
  2. 为绵羊行动更新董事会
  3. 做每一个狼的动作,并在下一步记录它们。
  4. 更新狼行动的董事会。

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

  • 将 Board 划分为不同的区域,并将每个线程分配给一个区域。您将无法弄清楚如何将其从一个区域移动到另一个区域。

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

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

于 2010-09-14T23:10:41.253 回答