java - 使用 Repast Simphony 的意外结果

标签 java repast-simphony

我需要使用 Repast Simphony 作为模拟器开发 Java 版本的 Iterated Prisoner Dilemma

想法是每个 Player 都是一个 agent,我们有一个 n x nPlayer 网格无法移动。每个 Player 必须与 4 个邻居(北部、南部、西部和东部)一起玩,根据每轮 4 个不同游戏的结果找到最佳策略。

由于 Repast Simphony 中没有内置系统在代理之间交换消息,我不得不实现某种解决方法来处理代理的同步(A vs B 和 B vs A 应该算作同一轮,这就是它们需要同步的原因)。

这是通过将每一轮视为:

  • 玩家 i 为 4 个敌人中的每一个选择下一步行动
  • 玩家 i 向 4 个敌人中的每一个发送正确的移动
  • Player i 等待 4 个敌人中的每一个回复

根据我对 Repast Simphony 的理解,计划的方法是顺序的(没有代理级并行性),这意味着我被迫以不同于发送方法的方法进行等待(计划为较低的优先级以确保在开始等待之前完成所有发送)。

这里的问题是,尽管收到了所有 4 个预期的消息(至少这是打印的内容),但一旦等待方法启动,它就会报告收到的元素少于 4 个。

这是从 Player 类中获取的代码:

// myPoint is the location inside the grid (unique, agents can't move and only one per cell is allowed)
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((myPoint == null) ? 0 : myPoint.hashCode());
    return result;
}

// Returns enemy's choice in the previous round
private byte getLastPlay(Player enemy) {
    return (neighbors.get(enemy)[1]) ? COOPERATE : DEFECT;
}

// Elements are saved as (player, choice)
private void receivePlay(Player enemy, byte play) {
    System.out.println(this + " receives (" + play + ") from " + enemy);
    while (!playSharedQueue.add(new Object[] { enemy, play })){
        // This doesn't get printed, meaning that the insertion is successful!
        System.out.println(this + " failed inserting");
    }
}

@ScheduledMethod(start = 1, interval = 1, priority = 10)
public void play() {
    System.out.println(this + " started playing");
    // Clear previous plays
    playSharedQueue.clear();
    for (Player enemy : neighbors.keySet()) {
        // properties[0] = true if we already played together
        // properties[1] = true if enemy choose to cooperate on the previous round
        Boolean[] properties = neighbors.get(enemy);
        // Choose which side we take this time
        byte myPlay;
        if (properties[0]) {
            // First time that we play, use memory-less strategy
            myPlay = (Math.random() <= strategy[0]) ? COOPERATE : DEFECT;
            // Report that we played
            properties[0] = false;
            neighbors.put(enemy, properties);
        } else {
            // We already had a round, use strategy with memory
            byte enemyLastPlay = enemy.getLastPlay(this);
            // Choose which side to take based on enemy's previous decision
            myPlay = (Math.random() <= strategy[(enemyLastPlay) == COOPERATE ? 1 : 2]) ? COOPERATE : DEFECT;
        }
        // Send my choice to the enemy
        System.out.println(this + " sent (" + myPlay + ") to " + enemy);
        enemy.receivePlay(this, myPlay);
    }
}

// Waits for the results and processes them
@ScheduledMethod(start = 1, interval = 1, priority = 5)
public void waitResults() {
    // Clear previous score
    lastPayoff = 0;
    System.out.println(this + " waits for results [" + playSharedQueue.size() + "]");
    if (playSharedQueue.size() != 4) {
        // Well, this happens on the first agent :(
        System.exit(1);
    }
    // ... process ...
}

这是控制台输出,因此您可以看到所有内容似乎都已发送和接收,没有任何问题(使用 3 x 3 网格):

Player[2, 0] started playing
Player[2, 0] sent (0) to Player[2, 1]
Player[2, 1] receives (0) from Player[2, 0]
Player[2, 0] sent (0) to Player[2, 2]
Player[2, 2] receives (0) from Player[2, 0]
Player[2, 0] sent (0) to Player[0, 0]
Player[0, 0] receives (0) from Player[2, 0]
Player[2, 0] sent (0) to Player[1, 0]
Player[1, 0] receives (0) from Player[2, 0]
Player[1, 2] started playing
Player[1, 2] sent (1) to Player[2, 2]
Player[2, 2] receives (1) from Player[1, 2]
Player[1, 2] sent (1) to Player[0, 2]
Player[0, 2] receives (1) from Player[1, 2]
Player[1, 2] sent (1) to Player[1, 0]
Player[1, 0] receives (1) from Player[1, 2]
Player[1, 2] sent (1) to Player[1, 1]
Player[1, 1] receives (1) from Player[1, 2]
Player[0, 2] started playing
Player[0, 2] sent (1) to Player[2, 2]
Player[2, 2] receives (1) from Player[0, 2]
Player[0, 2] sent (1) to Player[0, 0]
Player[0, 0] receives (1) from Player[0, 2]
Player[0, 2] sent (1) to Player[0, 1]
Player[0, 1] receives (1) from Player[0, 2]
Player[0, 2] sent (1) to Player[1, 2]
Player[1, 2] receives (1) from Player[0, 2]
Player[0, 1] started playing
Player[0, 1] sent (1) to Player[2, 1]
Player[2, 1] receives (1) from Player[0, 1]
Player[0, 1] sent (1) to Player[0, 0]
Player[0, 0] receives (1) from Player[0, 1]
Player[0, 1] sent (1) to Player[0, 2]
Player[0, 2] receives (1) from Player[0, 1]
Player[0, 1] sent (1) to Player[1, 1]
Player[1, 1] receives (1) from Player[0, 1]
Player[1, 0] started playing
Player[1, 0] sent (0) to Player[2, 0]
Player[2, 0] receives (0) from Player[1, 0]
Player[1, 0] sent (0) to Player[0, 0]
Player[0, 0] receives (0) from Player[1, 0]
Player[1, 0] sent (0) to Player[1, 1]
Player[1, 1] receives (0) from Player[1, 0]
Player[1, 0] sent (0) to Player[1, 2]
Player[1, 2] receives (0) from Player[1, 0]
Player[1, 1] started playing
Player[1, 1] sent (0) to Player[2, 1]
Player[2, 1] receives (0) from Player[1, 1]
Player[1, 1] sent (0) to Player[0, 1]
Player[0, 1] receives (0) from Player[1, 1]
Player[1, 1] sent (0) to Player[1, 0]
Player[1, 0] receives (0) from Player[1, 1]
Player[1, 1] sent (0) to Player[1, 2]
Player[1, 2] receives (0) from Player[1, 1]
Player[2, 2] started playing
Player[2, 2] sent (0) to Player[2, 0]
Player[2, 0] receives (0) from Player[2, 2]
Player[2, 2] sent (0) to Player[2, 1]
Player[2, 1] receives (0) from Player[2, 2]
Player[2, 2] sent (0) to Player[0, 2]
Player[0, 2] receives (0) from Player[2, 2]
Player[2, 2] sent (0) to Player[1, 2]
Player[1, 2] receives (0) from Player[2, 2]
Player[0, 0] started playing
Player[0, 0] sent (1) to Player[2, 0]
Player[2, 0] receives (1) from Player[0, 0]
Player[0, 0] sent (1) to Player[0, 1]
Player[0, 1] receives (1) from Player[0, 0]
Player[0, 0] sent (1) to Player[0, 2]
Player[0, 2] receives (1) from Player[0, 0]
Player[0, 0] sent (1) to Player[1, 0]
Player[1, 0] receives (1) from Player[0, 0]
Player[2, 1] started playing
Player[2, 1] sent (1) to Player[2, 0]
Player[2, 0] receives (1) from Player[2, 1]
Player[2, 1] sent (1) to Player[2, 2]
Player[2, 2] receives (1) from Player[2, 1]
Player[2, 1] sent (1) to Player[0, 1]
Player[0, 1] receives (1) from Player[2, 1]
Player[2, 1] sent (1) to Player[1, 1]
Player[1, 1] receives (1) from Player[2, 1]
Player[2, 2] waits for results [1]

正如您在最后一行中看到的,playSharedQueue.size()1 我真的不明白为什么。

如果方法调用是顺序的,waitResults()方法在 9 次 play()` 执行后调用,并且假设每个正确发送 4 条消息,我找不到原因那个大小仍然是 1。

当然,一切都是顺序的意味着没有同步问题,即使我在使用LinkedBlockingQueue而不是HashSet时遇到了同样的问题。

你们有什么提示吗?

最佳答案

一段时间后,我再次打开代码,发现我犯了一个简单但严重的错误:

@ScheduledMethod(start = 1, interval = 1, priority = 10)
public void play() {
    System.out.println(this + " started playing");
    // Clear previous plays
    playSharedQueue.clear();

playSharedQueue.clear(); 被执行以清除之前的结果,但是由于调用是连续的,第二个玩家将在第一个玩家向他发送他的游戏后调用它,所以游戏是丢弃。

waitResults 末尾移动该行解决了这个问题。

关于java - 使用 Repast Simphony 的意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34906724/

相关文章:

java - java 安全性的加密技术不起作用并抛出错误的填充异常

java - 如何检查Spring Boot应用程序在自动配置类中是否有某个注释

repast-simphony - 吃饭 Java : Problem of Creating Multiple types of Custom Edge

repast-simphony - 就餐西蒙尼 : Scheduling a global behavior as Poisson process with random intervals

java - 如何修复repast.simphony.runtime.RepastMain生成的错误?

repast-simphony - 我可以在运行 GUI 中显示parameters.xml 中定义的参数顺序吗?

java - 如何在 JSP 中设置下拉/选择的默认值?

Java volatile 关键字 - 我需要它吗?

java - Gradle依赖问题,java.lang.NoClassDefFoundError,但是编译通过

scheduler - Repast Symphony 调度方法优先级和坐席优先级