@@ -138,9 +138,8 @@ class KMeansPPSearch(Search):
138138 allocated_cluster_index
139139 )
140140 # 乱数で選択
141- index = random.randint(0, len(cluster_entity_ids) - 1)
142- # 選択したエンティティIDを結果として設定
143- self._result = cluster_entity_ids[index]
141+ if cluster_entity_ids:
142+ self._result = random.choice(cluster_entity_ids)
144143
145144 return self
146145` ` `
@@ -158,13 +157,180 @@ class KMeansPPSearch(Search):
158157 - 目標にたどり着く前に探索対象が変わってしまうため、なかなか目標にたどり着けない
159158 - 色んなところにランダムに探索対象を選択することで、効率的な探索ができない
160159- すでに探索したエンティティを再度探索対象として選択してしまうため、効率的な探索ができない
160+ - 近くに未探索のエンティティがあるのに、遠くのエンティティを探索対象として選択してしまう
161161
162162などの問題があります。
163163
164164# # 課題
165165
166166` KMeansPPSearch` モジュールを改善し、より効率的な探索を行うモジュールを実装して見てください。
167167
168+ ` ` ` {warning}
169+ ここに上げた問題以外にも、改善すべき点が存在すると思うので、それを改善していただいても構いません。
170+ ` ` `
171+
168172# ## 探索対象がステップごとに変わってしまう問題
169173
174+ ` ` ` {admonition} 方針のヒント
175+ :class: tip dropdown
176+
177+ 一度選択した探索対象に到達するまで、探索対象を変更しないようにする
178+ ` ` `
179+
180+ ` ` ` {admonition} プログラム例
181+ :class: tip dropdown
182+
183+ ` ` ` ` python
184+ def calculate(self) -> Search:
185+ # 自エージェントのエンティティIDを取得
186+ me: EntityID = self._agent_info.get_entity_id()
187+ # 自エージェントが所属するクラスターのインデックスを取得
188+ allocated_cluster_index: int = self._clustering.get_cluster_index(me)
189+ # クラスター内のエンティティIDを取得
190+ cluster_entity_ids: list[EntityID] = self._clustering.get_cluster_entity_ids(
191+ allocated_cluster_index
192+ )
193+
194+ # 探索対象をすでに選んでいる場合
195+ if self._result:
196+ # 自エージェントのいる場所のエンティティIDを取得
197+ my_position = self._agent_info.get_position_entity_id()
198+ # 探索対象の場所のエンティティIDを取得
199+ target_position = self._world_info.get_entity_position(self._result)
200+ # 自エージェントのいる場所と探索対象の場所が一致している場合、探索対象をリセット
201+ if my_position == target_position:
202+ # 探索対象をリセット
203+ self._result = None
204+
205+ # 探索対象が未選択の場合
206+ if not self._result and cluster_entity_ids:
207+ self._result = random.choice(cluster_entity_ids)
208+
209+ return self
210+ ` ` `
211+
170212# ## すでに探索したエンティティを再度探索対象として選択してしまう問題
213+
214+ ` ` ` {admonition} 方針のヒント
215+ :class: tip dropdown
216+
217+ すでに探索したエンティティを何かしらの方法で記録し、再度探索対象として選択しないようにする
218+ ` ` `
219+
220+ ` ` ` {admonition} プログラム例
221+ :class: tip dropdown
222+
223+ ` ` ` ` python
224+ def __init__(
225+ self,
226+ agent_info: AgentInfo,
227+ world_info: WorldInfo,
228+ scenario_info: ScenarioInfo,
229+ module_manager: ModuleManager,
230+ develop_data: DevelopData,
231+ ) -> None:
232+ super().__init__(
233+ agent_info, world_info, scenario_info, module_manager, develop_data
234+ )
235+ self._result: Optional[EntityID] = None
236+
237+ self._logger = get_agent_logger(
238+ f"{self.__class__.__module__}.{self.__class__.__qualname__}",
239+ self._agent_info,
240+ )
241+
242+ self._clustering: Clustering = cast(
243+ Clustering,
244+ module_manager.get_module(
245+ "KMeansPPSearch.Clustering",
246+ "adf_core_python.implement.module.algorithm.k_means_clustering.KMeansClustering",
247+ ),
248+ )
249+
250+ self.register_sub_module(self._clustering)
251+
252+ # 探索したいエンティティIDのリスト(追加)
253+ self._search_entity_ids: list[EntityID] = []
254+
255+ def calculate(self) -> Search:
256+ # 探索したいエンティティIDのリストが空の場合
257+ if not self._search_entity_ids:
258+ # 自エージェントのエンティティIDを取得
259+ me: EntityID = self._agent_info.get_entity_id()
260+ # 自エージェントが所属するクラスターのインデックスを取得
261+ allocated_cluster_index: int = self._clustering.get_cluster_index(me)
262+ # クラスター内のエンティティIDを取得(変更)
263+ self._search_entity_ids: list[EntityID] = (
264+ self._clustering.get_cluster_entity_ids(allocated_cluster_index)
265+ )
266+
267+ # 探索対象をすでに選んでいる場合
268+ if self._result:
269+ # 自エージェントのいる場所のエンティティIDを取得
270+ my_position = self._agent_info.get_position_entity_id()
271+ # 探索対象の場所のエンティティIDを取得
272+ target_position = self._world_info.get_entity_position(self._result)
273+ # 自エージェントのいる場所と探索対象の場所が一致している場合、探索対象をリセット
274+ if my_position == target_position:
275+ # 探索したいエンティティIDのリストから探索対象を削除
276+ self._search_entity_ids.remove(self._result)
277+ # 探索対象をリセット
278+ self._result = None
279+
280+ # 探索対象が未選択の場合(変更)
281+ if not self._result and self._search_entity_ids:
282+ self._result = random.choice(self._search_entity_ids)
283+
284+ return self
285+ ` ` `
286+
287+ # ## 近くに未探索のエンティティがあるのに、遠くのエンティティを探索対象として選択してしまう
288+
289+ ` ` ` {admonition} 方針のヒント
290+ :class: tip dropdown
291+
292+ エンティティ間の距離を計算し、もっとも近いエンティティを探索対象として選択する
293+ ` ` `
294+
295+ ` ` ` {admonition} プログラム例
296+ :class: tip dropdown
297+
298+ ` ` ` ` python
299+ def calculate(self) -> Search:
300+ # 探索したいエンティティIDのリストが空の場合
301+ if not self._search_entity_ids:
302+ # 自エージェントのエンティティIDを取得
303+ me: EntityID = self._agent_info.get_entity_id()
304+ # 自エージェントが所属するクラスターのインデックスを取得
305+ allocated_cluster_index: int = self._clustering.get_cluster_index(me)
306+ # クラスター内のエンティティIDを取得
307+ self._search_entity_ids: list[EntityID] = (
308+ self._clustering.get_cluster_entity_ids(allocated_cluster_index)
309+ )
310+
311+ # 探索対象をすでに選んでいる場合
312+ if self._result:
313+ # 自エージェントのいる場所のエンティティIDを取得
314+ my_position = self._agent_info.get_position_entity_id()
315+ # 探索対象の場所のエンティティIDを取得
316+ target_position = self._world_info.get_entity_position(self._result)
317+ # 自エージェントのいる場所と探索対象の場所が一致している場合、探索対象をリセット
318+ if my_position == target_position:
319+ # 探索したいエンティティIDのリストから探索対象を削除
320+ self._search_entity_ids.remove(self._result)
321+ # 探索対象をリセット
322+ self._result = None
323+
324+ # 探索対象が未選択の場合
325+ if not self._result and self._search_entity_ids:
326+ nearest_entity_id: Optional[EntityID] = None
327+ nearest_distance: float = float("inf")
328+ me: EntityID = self._agent_info.get_entity_id()
329+ # 探索対象の中で自エージェントに最も近いエンティティIDを選択(変更)
330+ for entity_id in self._search_entity_ids:
331+ distance = self._world_info.get_distance(me, entity_id)
332+ if distance < nearest_distance:
333+ nearest_entity_id = entity_id
334+ nearest_distance = distance
335+ self._result = nearest_entity_id
336+ ` ` `
0 commit comments