在列表中查找项目的 'source turtle'

Find the 'source turtle' of an item in a list

我想追踪一个被小偷偷走的钱包的路径。该模型应该创建一个小偷网络,每个小偷都有自己的袋子,用来放被盗的物品(我将这个物品 - 钱包 - 设置为自己)。

假设 thief1 在他自己的包里有 [wallet1 wallet2 wallet4] 而他的邻居有 [wallet1 wallet3] 因为 wallet1 被添加到他自己的包里。

如果邻居带着包 [wallet1 wallet3] 想随机挑选两件物品中的一件 return 报警,例如 wallet1 (这可以使用 [let picked_wallet one-of turtle-set my-bag]), 我怎样才能添加一个 'tag' 或者可以告诉我第一个偷那个钱包的小偷是小偷 1 的东西?

globals [this-wallet]

breed[thieves thief]
thieves-own [my-bag wallet-id]

to setup
  clear-all

  create-thieves 5
  ask thieves [  set my-bag []  create-links-to other thieves ]
  ask one-of thieves [ set this-wallet self set my-bag fput self my-bag ask link-neighbors [set my-bag fput this-wallet my-bag print "Neighbours " show my-bag  ]]
  ask one-of thieves [ set this-wallet self set my-bag fput self my-bag ask link-neighbors [set my-bag fput this-wallet my-bag print "Neighbours " show my-bag  ]]
  ask thieves [show link-neighbors show my-bag]
   reset-ticks

end

你问了

how can I add a 'tag' or something that can tell me that the first thief to stole that wallet was the thief1?

我不清楚"stealing a wallet"对应的是什么操作。将钱包放在某人名单上的代理人是否在偷窃?或者它被列入名单的人?

在你的例子中,你有两个不同的人 "wallet1" 在他们的名单上,所以我也不清楚谁 "has" 钱包。一个钱包怎么能同时放在两个地方?事实上不止两个地方,当它被放在一个盗贼名单上时,它就被放在了所有的盗贼名单上。该操作应该代表什么?那是"stealing"吗?

您是否想弄清楚 wallet1 的众多副本中的哪一个最先出现在任何代理人的名单上?当然这有点难,因为代理集总是以随机顺序处理,所以您显示的代码没有给出谁先得到它的线索。

我的意思是,您拥有的数据结构 似乎不能很好地表示真实世界的操作,如果这不是混淆当前谁首先将钱包放在他们的列表中的问题,这就是我想你在问的问题,它肯定会混淆其他问题。您显示的更新列表的操作使得不可能确定哪个小偷先得到它。

这让我很困惑。我认为如果只存在 wallet1 的一个副本,并且一次只在一个代理人的列表中,并且代理人的列表只有一个条目,那么您的编码会容易得多,并且您有一个 "steal-wallet" 从一个代理人的列表中删除钱包并将其放在另一个不同代理人的列表中的程序。那么具体是什么时间就一目了然了。

或者这些列表是否应该代表代理人对钱包 存在 的了解?或者它们是否代表所有历史上任何人曾经拥有的所有钱包,在这种情况下,"same" 钱包可能出现很多次,每次代表不同的所有者,甚至可能是同一个钱包和同一个所有者多次被盗和被盗回来,所以即使那对事实(钱包 ID 和新所有者)也不是唯一的。

一方面,如果每个人最终都会得到相同的列表,那么找个地方把列表放一次就可以了——不要给每个人一份,一份就可以了。该列表甚至不需要由任何人拥有——它可以只是一个全局变量。那会简化很多。那么你只有一个钱包,每次它改变所有者你都可以在主列表中添加一个条目。

条目应该包含什么?当然不是钱包本身,因为它可以传递。可能您需要一个描述刚刚发生的交易的子列表,因此您需要一个包含 [wallet-id, last-owner-id, current-owner-id, time-it-changed-hands] 作为条目的子列表主全局列表。

据此,您至少可以在概念上重建谁拥有列表第一、第二、第三、.. 或最后,现在谁拥有它,任何您想要的。或者,如果您总是 "lput" 将最新事件作为列表中的最后一项,那么您甚至不需要时间戳,除非您通过对列表进行排序而丢失信息,因为第一个所有者将是列表中第一个具有该钱包 ID 的条目。问题解决了,在概念上。仍然您可能希望某天对列表进行排序,因此如果您愿意的话,在其上加上时间戳将允许您稍后恢复顺序。

在所有讨论的结论中,我建议首先找出谁拥有 wallet1 是这样的: * 完全删除每个代理上的我的列表。
使用定义为全局的单个列表。

  • 将钱包视为真实的,并且在任何时候都只有一个钱包副本。

  • 定义程序 "steal-wallet"、"create-wallet" 和 "destroy-wallet" 将钱包从一个所有者转移到另一个所有者,并将交易记录为 4 个事实的子列表主列表。主列表将是列表的列表。

  • 主列表可能被命名为 "transactions",因为这是它记录的内容。

  • 然后,从概念上讲,您将拥有回答有关钱包的生活史或小偷生活史的任何问题所需的所有信息。您不必维护相同信息的 20 个不同副本。

  • 并且可以很容易地查看所有小偷并查看哪个小偷有钱包,而无需查看交易列表。 (虽然,该信息将对应于关于该钱包的交易列表中的最后一个条目。)

或者——也许我完全误解了这些列表的含义。

将球(或钱包)传回给您。

为了回应您对我上一个答案的评论,这里有一个新答案。

嗯,病毒问题和钱包问题不同,需要不同的数据结构。

不过,病毒传播可以建模为一系列交易,因此使用全球交易主列表来跟踪发生的事情的想法仍然是一种可行的方法。

您还可以在每个代理上保留一份列表,说明他们从谁那里感染了病毒以及何时感染了病毒,但是如果只有一个主列表就显得多余了——您可以简单地按代理过滤交易的主列表以准确查看与您在代理级别的许多列表中尝试保留的信息相同。我不确定您为什么不喜欢这种方法。

保留一个列表比保留多个列表要干净得多。您可以向代理列表询问的任何问题也可以通过搜索全局列表来回答。

有一个冗余来查看正在发生的事情和简化你将用来传播病毒的 ASK 命令是有意义的——这样你就可以存储在代理级别代理当前是否被感染?和颜色代码感染代理区分他们从未感染代理和完全恢复?特工又死了?代理商。

甚至可以将其简化为具有合法值 "healthy" "infected" 和 "recovered" 的单个状态变量和一个现在免疫?旗帜。这足以弄清楚谁具有传染性,谁被感染,谁可能被感染,谁已经康复,谁已经死亡等等

当然,如果你是流行病学家并试图追踪感染的来源("patient zero"),你可以添加一个变量来显示每个人被感染的时间和时间,并写一些长的递归代码逐步追溯链表开始的位置。或者,您可以在谁感染了谁以及何时感染了主列表的简单单次过滤过程中得到相同的答案。

也许最简单的方法是 "cheating" 并且您想扮演医生而不是上帝,并且您想展示如何一步一步地追踪它?或者你想展示流行病学家如何花费大量精力构建一个 "tree" 图表来显示感染从哪里开始以及它如何传播到不同的分支?

这是一个有趣的问题,但这不是你问的问题。

如果你想为列表中的项目找到终极源龟,你需要修改你的数据结构。一种方法(困难的方法)是在每只乌龟的列表中存储更多信息——因此在将病毒添加到列表时,您还添加了时间戳和来源乌龟。可能您可以将此信息作为三元组存储在列表中,例如 [ source-agent-id tick-acquired virus-type ] 这样每个代理都会有一个这样的三元组列表。那行得通。这是一种方法。

这将需要您在将病毒列入他们的列表的过程中增加一些复杂性。它必须构建一个包含 3 个项目的列表,并将该列表放入它感染的任何代理的目标 my-list 中。 (在你的情况下,病毒似乎具有 100% 的传染性,任何携带它的人都会把它传染给其他人!)

所以你的 ASK-TURTLES 逻辑会稍微复杂一点。您可以通过很少的报告例程来打包或解包三元组列表来管理复杂性。

或者,如果要管理的列表较少,您可以让 ASK-TURTLES 逻辑存储一系列事务,您可以将其编码为 4 项列表:[ source-id target-id virus-type tick-infected ] 并将其存储在全局变量的主列表列表中。您仍然可能希望在感染下一个代理时设置 "status" 和 "immune-now?" 的目标乌龟变量,以简化识别哪些乌龟具有传染性以及哪些乌龟免疫以简化下一步在哪里你会要求具有传染性的海龟感染没有免疫力且在给定半径内的海龟等等