MAS コミュニティ
artisoc質問用掲示板(アーカイブ)
  
質問掲示板は移転しました。新掲示板はこちら

質問  (回答受付中)

[artisocモデル] 相続制度の実現に当たって子供リストを取得したかった。
質問者: la manoさん , 質問日時: 2021/01/08 01:38
エージェントは家や生産手段(農地等)などの用途として土地を所有するが、エージェントが死亡した際に過去に自らが出産したエージェントのうち、最年長者に所有権を移すという処理を行いたい。その為には子供を纏めたエージェント集合を保持する必要性が出てくる。然しこのエージェント集合が想定しない挙動を見せたため、原因及び解決策を知りたい。

処理の流れとしては、誕生後、(親がいれば)親の座標に移り(親の情報は直前に出産した個体をグローバルなエージェント変数に記録)、親の家に余裕があれば同居、なければ新しく近くに家を建てる。職場として近場の最も栄養価の高い土地に農地を建設する。以上の処理が出来なければ(十分な土地がなければ)自死する。
毎ステップ、家と農地を往復し、農地にいる時土地の栄養価に比例した食料を得て、家にいるとき、手持ちの食料が十分に多ければ余分を家に備蓄する。家の備蓄量が十分に多ければ、備蓄を消費して出産する。

親から子へリンクを結んだものが画像(四角いエージェントは土地エージェントで、青は空き地の栄養価の度合いを示し、緑は農地、桃は家を示している。人エージェントは赤点(数字はID))https://imgur.com/a/SOzsi0T (外部リンク)

明らかに出産したとは言い難い遠方のエージェントと紐づいていることが分かる。また、複数の自称親が特定の子に矢印を伸ばしていることが分かる。

以上の現象に心当たりがあればご教授願いたい。

以下は原因究明に当たって分かったこと。
子から親に向けてリンクを結ぼうとすると親から子と比較すると以上が少ないが時がたつと異常は増すことがある。
周囲の空き地が無くなったタイミングで異常が起きだすようだ。
killagtされたはずのエージェントと同一のIDのエージェントが描画されている。削除から同一IDエージェントが生成された形跡なし。また、kill類似関数に変更しても同様。


以下は人エージェントの全文。デバグの為に余分な文があり見辛いが、参考にされたい。
Agt_Init{
my.食料 = 5 //即餓死を防ぐ。一応2世代目は親から受け取っている。出産にそれ以上の費用なし
my.生年 = getcountstep()//産まれたタイミングを記録
dim 親 as agt
dim neighbor0 as agtset
dim neighbor as agtset
dim 親の家 as agt //なぜかuniverse.地域.親.家とかやるとバグるので(数字だから?)クッション
ClearAgtSet(my.子)
ClearAgtSet(my.親)
if universe.地域.親 then//親がいる
print("親がいる")
親 = universe.地域.親
addagt(my.親, 親)
println("生成された人" & Cstr(my.ID) & "親" & Cstr(親.ID))
同じ位置にする(my, 親)
MakeOneAgtsetAroundOwn(neighbor0, 3, universe.地域.土地, False) //周囲の荒地を探している
makecommonagtset(neighbor, neighbor0, universe.荒地)
親の家 = 親.家
if countagtset(親の家.居住者) < 3 then
my.家 = 親.家
addagt(my.所有土地, my.家) //相続をさせたいが未実装
同じ位置にする(my, my.家)
if countagtset(neighbor) then
sortagtset(neighbor, "豊穣", false) //職場
my.職場 = pickupagt(neighbor, 0) //一番豊かな土地を選択
addagt(my.所有土地, my.職場) //未実装
delagtset2(universe.荒地, my.職場)
My.職場.色 = COLOR_GREEN //描画の為
my.目的地 = my.職場 //往復の為
addagt(my.家.居住者, my)
else//一度産んで殺している
print("家飛び出るも行き場なく死")
killagt(my)
end if

elseif countagtset(neighbor) > 1 then //親の家満室 家を出る
家と農地を探す(neighbor)
else
print("家ない")
killagt(My)
end if

//addagt(親.子, my)
else//親がいない つまり第一世代目 場合分けしないと親が0でバグる
print("親がいない")
my.X = rnd() * getheightspace(universe.地域) //逆だったかもだけど正方形なのでヨシ
my.Y = rnd() * getwidthspace(universe.地域)
MakeOneAgtsetAroundOwn(neighbor0, 3, universe.地域.土地, False)
makecommonagtset(neighbor, neighbor0, universe.荒地)
家と農地を探す(neighbor)
end if
}

sub 同じ位置にする(対象 as agt, 移動先 as agt){
対象.X = 移動先.X
対象.Y = 移動先.Y}


sub 家と農地を探す(neighbor as agtset){
if countagtset(neighbor) then //周囲に荒地がある
sortagtset(neighbor, "豊穣", false)//周囲で一番豊かな土地を探す
my.職場 = pickupagt(neighbor, 0) //集合から除外して家と被らないようにしている
addagt(my.所有土地, my.職場)

同じ位置にする(my, my.職場)

if countagtset(neighbor) then//
my.家= pickupagt(neighbor, Int(Rnd() * CountAgtset(neighbor)))//適当な空き地に家を建てて住む
addagt(my.所有土地, my.家)
delagtset2(universe.荒地, my.家)
My.家.色 = COLOR_MAGENTA
delagtset2(universe.荒地, my.職場)
My.職場.色 = COLOR_GREEN
my.目的地 = my.家
addagt(my.家.居住者, my)
else//農地を用意できなければ死
print("農地ない")
killagt(my)
end if
else//家を用意できなければ死
print("家ない")
killagt(My)
end if}

Agt_Step{
println("step" & Cstr(my.ID))
//家と職場を往復
dim one as agt
if My.X == My.家.X and My.Y == My.家.Y then//家に着いたら
my.目的地 = My.職場 //目的地のくだりは往復の為

if my.食料 > 10 then //手持ちの食料を10より多く持ってたらその分家に置いておく
My.家.備蓄 = my.家.備蓄 + my.食料 - 10
my.食料 = 10
end if

if my.家.備蓄 > 10 then//備蓄が十分あれば子を産む
universe.地域.親 = my
println("creating by " & Cstr(my.ID))
one = createagt(universe.地域.人)
if my.X != one.X or my.Y != one.Y then //バグの検知
println(Cstr(my.X) & Cstr(my.Y) & Cstr(one.X) & Cstr(one.Y))
end if
my.家.備蓄 = my.家.備蓄 -5

addagt(my.子, one) //なぜかバグり遠方に子供が出来たり複数の人が親権を主張したりする

end if

elseif My.X == My.職場.X and My.Y == My.職場.Y then
my.目的地 = My.家
my.食料 = my.食料 + my.職場.豊穣 * 10 //農地に着いたら収穫
end if
pursue(my.目的地, 1)


my.食料 = my.食料 -1 //食料を消費
if my.食料 < 0 then//餓死と老死 区別するためだけに場合分けている
println("餓死削除された人" & Cstr(my.ID))
delagtset2(my.家.居住者, my)
if countagtset(my.家.居住者) == 0 then
addagt(universe.荒地, my.家)
my.家.色 = My.家.豊穣*256
my.家.備蓄 = 0
end if
addagt(universe.荒地, my.職場)
My.職場.色 = My.職場.豊穣*256
killAgt(my)
elseif my.生年 + 50< getcountstep() then
println("老死削除された人" & Cstr(my.ID)) //死んだ後も何故か表示され続ける
delagtset2(my.家.居住者, my)
if countagtset(my.家.居住者) == 0 then //なぜか!=1でも上手くいっていた
addagt(universe.荒地, my.家) //誰も住んでいない家を自動で解体する 現実でも出来たらよいが…
my.家.色 = My.家.豊穣*256
my.家.備蓄 = 0
end if
addagt(universe.荒地, my.職場) //職場は共用じゃないので破壊
My.職場.色 = My.職場.豊穣*256
terminateAgt(my)
end if

}



▼ 全ての回答


ツリーの構成が分からないので詳細は分かりませんが、

例えば、Universe.Map.Personという構成で空間とエージェントを作成し、
PersonにParentsとChildrenというエージェント集合型変数を追加します。
このとき、personの生成する毎にAddAgtでParentsとChildrenにエージェントを追加して
親子関係を保持することができます。

次に、TerminateAgtで親Personを削除した場合、
子Personの保持するParentsの親Personは自動的に削除されます。

また、
if universe.地域.親 then//親がいる
と記載している箇所がありますが、

universe.地域.親 がエージェントの定義だとすると、
親が1人以上いる場合は、
if CountAgt(universe.地域.親) > 0 then//親がいる
と記述すべきです。

複数の親を検索するときは、
Dim 親AgtSet As AgtSet, 親Agt As Agt

MakeAgtSet(親AgtSet, universe.地域.親)
For Each 親Agt In 親AgtSet
// 変数を参照する場合は、「親Agt.家」などと記述します。
Next 親Agt
個別の

それから、ツリーで定義した変数名とローカル変数を同じ名前で定義するとややこしいので、
別名をつけることをおすすめします。

回答者: m.tamada さん , 回答日時: 2021/01/12 16:29
>>m.tamada さん
回答ありがとうございます。

親子関係についてですが、人エージェントの下に親エージェント集合や子エージェント集合を持たせここで保持させることはやっていますが、その動作が不可解な状況です。これはterminateagtなどの仕様では説明を付けることが出来ません。

また、Universe.地域.親はエージェント変数ですが、

if CountAgt(universe.地域.親) > 0 then

等のように表記すると、シミュレートの最初に生成されるエージェントには親が存在せず、初期状態のエージェント変数には「0」が代入されており、エラーを吐くので0かそうでないかを判断するようにしていました。また、このuniverse.地域.親は厳密には直前に出産したagtを保持するようにしていて、これは子エージェントのinitでは親エージェントを特定する方法が他になかったからです。

また、今回の問題とは直接関係ないのですが、エージェント集合変数にエージェントを常に新しく登録したいエージェントを1つだけ代入したい(≒エージェント集合変数をエージェント変数のように振る舞わせたい)とき、恐らく

clearagtset(エージェント集合変数)
addagt(エージェント集合変数, エージェント)

とするべきかと思われますが、「無効なエージェント集合Idです」と出る為見送っています。

同名の変数については以後気を付けます

回答者: la mano さん , 回答日時: 2021/01/18 11:16
親子関係について、
Universe.地域.親 はエージェントだと思っていましたが、エージェント型の変数でしょうか?
ちなみに Universe.地域 が空間だとすると、空間のマス目の数だけ変数値を保持することになります。

この場合、CountAgt(universe.地域.親)は使えず、
Universe.地域.親(x,y,0)のような形式(0はレイヤ番号)で値を参照することになります。

エージェント集合変数にエージェントを常に新しく登録したいエージェントを1つだけ代入したい場合は、

clearagtset(エージェント集合変数)
addagt(エージェント集合変数, エージェント)

で問題ありません。
例えば、Universe直下に
ant(エージェント)
ants(エージェント集合型変数)
を定義し、Univ_Initに下記のルールを記述していただけると、正常に取得できることを確認できます。
どこにエージェント集合型変数を定義した場合にエラーとなるかおしえてください。

Dim antAgt As Agt

CreateAgt(Universe.ant)
CreateAgt(Universe.ant)
CreateAgt(Universe.ant)

ClearAgtSet(Universe.ants)
antAgt = Universe.ant(0)
AddAgt(Universe.ants, antAgt)
For Each antAgt In Universe.ants
PrintLn("ID=" & antAgt.ID)
Next antAgt

ClearAgtSet(Universe.ants)
antAgt = Universe.ant(1)
AddAgt(Universe.ants, antAgt)
For Each antAgt In Universe.ants
PrintLn("ID=" & antAgt.ID)
Next antAgt

回答者: m.tamada さん , 回答日時: 2021/01/18 14:15
>>m.tamada さん
Universe直下のエージェント型変数と空間直下のエージェント型変数では挙動が異なるということでしょうか。

エラーが起きるというのは

if my.家.備蓄 > 10 then//備蓄が十分あれば子を産む
universe.地域.親 = my

という部分に
clearagtset(universe.地域.親agtset)
addagt(universe.地域.親agtset, my)
という表現を書き加えたところエラーが生じました。
エージェント集合型は空間直下に定義しています

回答者: la mano さん , 回答日時: 2021/01/18 15:13
universe.地域.親agtset は変数なので、

clearagtset(universe.地域.親agtset)
addagt(universe.地域.親agtset, my)



clearagtset(universe.地域.親agtset(My.X, My.Y, 0))
addagt(universe.地域.親agtset(My.X, My.Y, 0), my)

と記述するといかがでしょうか?

回答者: さん , 回答日時: 2021/01/19 18:10



Copyright © KOZO KEIKAKU ENGINEERING Inc. All Rights Reserved.
( 会社情報 情報セキュリティ・個人情報について )