This commit is contained in:
Horldsence
2026-09-11 03:32:05 +08:00
parent 846b45e420
commit fc70d6edfd
14 changed files with 46032 additions and 65 deletions
+26 -21
View File
@@ -1,8 +1,9 @@
"""自检场景生成器(测试端专用)。
真值只进入测试与 CLI ``--self-test`` 入口,策略端仅见模拟器响应;
场景覆盖题面强调的边界情形:近圆域边界源、最小/最大接收半径两档,
以及问题4的定向源(含朝向背离圆心的朝外边界源)。
默认完全按题面生成:源总数 10~16 随机、位置在目标圆域内均匀分布、
频道互异(1..20 抽样)、有效接收半径 [1000,1500] 均匀。
边界情形(近圆域边界源、接收半径两档、定向朝外源)由专门测试显式构造。
"""
from __future__ import annotations
@@ -10,25 +11,29 @@ from __future__ import annotations
import math
from random import Random
from ..config import ProblemConfig
from .simulator import Source
def random_omni_scene(seed: int = 20260910, count: int = 10) -> list[Source]:
"""全向源场景:频道互异,含近圆域边界点,接收半径 1000/1500 交替。"""
if not 0 <= count <= 20:
raise ValueError("源数量须在 0..20")
def random_omni_scene(seed: int = 20260910, count: int | None = None,
config: ProblemConfig = ProblemConfig()) -> list[Source]:
"""全向源场景 [题面]:count=None 时源总数在 10..16 均匀随机。
位置在半径 omega_radius_m 圆域内按面积均匀(r = R*sqrt(u)),
有效接收半径在 [r_eff_min, r_eff_max] 均匀,频道从 1..20 无重复抽样。
"""
field = config.field
rng = Random(seed)
channels = rng.sample(range(1, 21), count)
if count is None:
count = rng.randint(field.source_count_min, field.source_count_max)
if not 0 <= count <= field.channel_max:
raise ValueError(f"源数量须在 0..{field.channel_max}")
channels = rng.sample(range(field.channel_min, field.channel_max + 1), count)
sources = []
for index, channel in enumerate(channels):
if index == 0:
radius = rng.uniform(1780.0, 1799.0) # 近圆域边界
elif index == 1 and count > 1:
radius = rng.uniform(1780.0, 1799.0)
else:
radius = rng.uniform(0.0, 1795.0)
for channel in channels:
radius = field.omega_radius_m * math.sqrt(rng.random())
angle = rng.uniform(0.0, 2 * math.pi)
r_eff = 1000.0 if index % 2 == 0 else 1500.0
r_eff = rng.uniform(field.r_eff_min_m, field.r_eff_max_m)
sources.append(Source(channel=channel,
x=radius * math.cos(angle),
y=radius * math.sin(angle),
@@ -36,21 +41,21 @@ def random_omni_scene(seed: int = 20260910, count: int = 10) -> list[Source]:
return sources
def mixed_scene(seed: int = 20260910, count: int = 10,
directional: int = 3) -> list[Source]:
def mixed_scene(seed: int = 20260910, count: int | None = None,
directional: int = 3,
config: ProblemConfig = ProblemConfig()) -> list[Source]:
"""问题4混合场景:count 个源中 directional 个为定向源。
改造 random_omni_scene 的前 directional 个源:近圆域边界的前两个定向源
朝向取"背离圆心"(发射半平面基本朝向域外,覆盖网格仍保证可发现,
即"朝外边界源不漏"验收情形),其余定向源朝向随机。
"""
if not 0 <= directional <= count:
raise ValueError("定向源数量须在 0..count")
sources = list(random_omni_scene(seed=seed, count=count))
sources = list(random_omni_scene(seed=seed, count=count, config=config))
directional = min(directional, len(sources))
rng = Random(seed + 1)
for index in range(directional):
source = sources[index]
if index < 2 and count > 1 and math.hypot(source.x, source.y) > 1700.0:
if index < 2 and len(sources) > 1 and math.hypot(source.x, source.y) > 1700.0:
heading = math.degrees(math.atan2(source.y, source.x)) % 360.0
else:
heading = rng.uniform(0.0, 360.0)
+6
View File
@@ -127,6 +127,12 @@ class LocalSimulator:
})
if not self.entered or self.exited:
return 200, self._not_accepted()
if path in ("/measure", "/clear") \
and self.virtual_time_s >= self.field.max_virtual_duration_s:
# 虚拟世界限时 360000s 防死循环 [题面/附件2 §4.5:达限结束测试]。
# 官方在达限时关闭接口;本地以 accepted=false 模拟,作为计划层
# 虚拟安全余量(search.virtual_reserve_s)失效时的兜底。
return 200, self._not_accepted()
if path == "/exit":
self.exited = True
return 200, self._ok({"exit_reason": EXIT_USER})