continual-foragax 0.24.2__tar.gz → 0.26.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/PKG-INFO +1 -1
  2. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/pyproject.toml +2 -2
  3. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/continual_foragax.egg-info/PKG-INFO +1 -1
  4. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/continual_foragax.egg-info/SOURCES.txt +2 -1
  5. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/env.py +34 -3
  6. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/objects.py +3 -0
  7. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/registry.py +49 -3
  8. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/tests/test_foragax.py +59 -0
  9. continual_foragax-0.26.0/tests/test_registry.py +381 -0
  10. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/README.md +0 -0
  11. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/setup.cfg +0 -0
  12. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/continual_foragax.egg-info/dependency_links.txt +0 -0
  13. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/continual_foragax.egg-info/entry_points.txt +0 -0
  14. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/continual_foragax.egg-info/requires.txt +0 -0
  15. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/continual_foragax.egg-info/top_level.txt +0 -0
  16. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/__init__.py +0 -0
  17. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/colors.py +0 -0
  18. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID100897.txt +0 -0
  19. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID100928.txt +0 -0
  20. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID100929.txt +0 -0
  21. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID100930.txt +0 -0
  22. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID100931.txt +0 -0
  23. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106714.txt +0 -0
  24. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106715.txt +0 -0
  25. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106716.txt +0 -0
  26. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106717.txt +0 -0
  27. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106718.txt +0 -0
  28. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106930.txt +0 -0
  29. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106931.txt +0 -0
  30. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106932.txt +0 -0
  31. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106933.txt +0 -0
  32. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106934.txt +0 -0
  33. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106935.txt +0 -0
  34. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106936.txt +0 -0
  35. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106937.txt +0 -0
  36. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106938.txt +0 -0
  37. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106939.txt +0 -0
  38. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106940.txt +0 -0
  39. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106941.txt +0 -0
  40. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106942.txt +0 -0
  41. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106943.txt +0 -0
  42. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106994.txt +0 -0
  43. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106995.txt +0 -0
  44. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106996.txt +0 -0
  45. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106997.txt +0 -0
  46. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106998.txt +0 -0
  47. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID106999.txt +0 -0
  48. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107000.txt +0 -0
  49. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107001.txt +0 -0
  50. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107002.txt +0 -0
  51. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107003.txt +0 -0
  52. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107004.txt +0 -0
  53. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107005.txt +0 -0
  54. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107006.txt +0 -0
  55. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107007.txt +0 -0
  56. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107008.txt +0 -0
  57. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107009.txt +0 -0
  58. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107010.txt +0 -0
  59. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107011.txt +0 -0
  60. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107012.txt +0 -0
  61. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107013.txt +0 -0
  62. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107014.txt +0 -0
  63. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107015.txt +0 -0
  64. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107016.txt +0 -0
  65. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107017.txt +0 -0
  66. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107018.txt +0 -0
  67. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107019.txt +0 -0
  68. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107020.txt +0 -0
  69. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107021.txt +0 -0
  70. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107022.txt +0 -0
  71. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107023.txt +0 -0
  72. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107024.txt +0 -0
  73. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107025.txt +0 -0
  74. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107026.txt +0 -0
  75. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107027.txt +0 -0
  76. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107028.txt +0 -0
  77. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107029.txt +0 -0
  78. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107030.txt +0 -0
  79. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107031.txt +0 -0
  80. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107032.txt +0 -0
  81. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107033.txt +0 -0
  82. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107034.txt +0 -0
  83. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107035.txt +0 -0
  84. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107036.txt +0 -0
  85. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107037.txt +0 -0
  86. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107038.txt +0 -0
  87. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107039.txt +0 -0
  88. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107040.txt +0 -0
  89. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107041.txt +0 -0
  90. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107042.txt +0 -0
  91. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107043.txt +0 -0
  92. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107044.txt +0 -0
  93. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107045.txt +0 -0
  94. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107046.txt +0 -0
  95. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107047.txt +0 -0
  96. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107048.txt +0 -0
  97. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107049.txt +0 -0
  98. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107050.txt +0 -0
  99. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107051.txt +0 -0
  100. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107052.txt +0 -0
  101. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107053.txt +0 -0
  102. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107054.txt +0 -0
  103. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107055.txt +0 -0
  104. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107056.txt +0 -0
  105. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107057.txt +0 -0
  106. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107058.txt +0 -0
  107. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107059.txt +0 -0
  108. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107060.txt +0 -0
  109. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107061.txt +0 -0
  110. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107062.txt +0 -0
  111. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107063.txt +0 -0
  112. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107064.txt +0 -0
  113. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107065.txt +0 -0
  114. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107066.txt +0 -0
  115. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107067.txt +0 -0
  116. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107068.txt +0 -0
  117. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107069.txt +0 -0
  118. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107070.txt +0 -0
  119. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID107071.txt +0 -0
  120. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID115808.txt +0 -0
  121. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID115812.txt +0 -0
  122. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID146811.txt +0 -0
  123. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156831.txt +0 -0
  124. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156835.txt +0 -0
  125. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156839.txt +0 -0
  126. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156843.txt +0 -0
  127. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156847.txt +0 -0
  128. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156851.txt +0 -0
  129. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156855.txt +0 -0
  130. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156859.txt +0 -0
  131. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156863.txt +0 -0
  132. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156867.txt +0 -0
  133. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156871.txt +0 -0
  134. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156875.txt +0 -0
  135. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156879.txt +0 -0
  136. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156883.txt +0 -0
  137. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/TG_SOUID156887.txt +0 -0
  138. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/elements.txt +0 -0
  139. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/metadata.txt +0 -0
  140. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/data/ECA_non-blended_custom/sources.txt +0 -0
  141. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/rendering.py +0 -0
  142. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/src/foragax/weather.py +0 -0
  143. {continual_foragax-0.24.2 → continual_foragax-0.26.0}/tests/test_benchmark.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: continual-foragax
3
- Version: 0.24.2
3
+ Version: 0.26.0
4
4
  Summary: A continual reinforcement learning benchmark
5
5
  Author-email: Steven Tang <stang5@ualberta.ca>
6
6
  Requires-Python: >=3.8
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "continual-foragax"
3
- version = "0.24.2"
3
+ version = "0.26.0"
4
4
  description = "A continual reinforcement learning benchmark"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -30,7 +30,7 @@ build-backend = "setuptools.build_meta"
30
30
  [tool]
31
31
  [tool.commitizen]
32
32
  name = "cz_conventional_commits"
33
- version = "0.24.2"
33
+ version = "0.26.0"
34
34
  tag_format = "$version"
35
35
  version_files = ["pyproject.toml"]
36
36
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: continual-foragax
3
- Version: 0.24.2
3
+ Version: 0.26.0
4
4
  Summary: A continual reinforcement learning benchmark
5
5
  Author-email: Steven Tang <stang5@ualberta.ca>
6
6
  Requires-Python: >=3.8
@@ -137,4 +137,5 @@ src/foragax/data/ECA_non-blended_custom/elements.txt
137
137
  src/foragax/data/ECA_non-blended_custom/metadata.txt
138
138
  src/foragax/data/ECA_non-blended_custom/sources.txt
139
139
  tests/test_benchmark.py
140
- tests/test_foragax.py
140
+ tests/test_foragax.py
141
+ tests/test_registry.py
@@ -1,12 +1,12 @@
1
- """JAX implementation of Foragax environment.
1
+ """JAX implementation of Forager environment.
2
2
 
3
- Source: https://github.com/andnp/Foragax
3
+ Source: https://github.com/andnp/Forager
4
4
  """
5
5
 
6
6
  from dataclasses import dataclass
7
7
  from enum import IntEnum
8
8
  from functools import partial
9
- from typing import Any, Dict, Tuple, Union
9
+ from typing import Any, Dict, Optional, Tuple, Union
10
10
 
11
11
  import jax
12
12
  import jax.numpy as jnp
@@ -75,6 +75,7 @@ class ForagaxEnv(environment.Environment):
75
75
  biomes: Tuple[Biome, ...] = (Biome(object_frequencies=()),),
76
76
  nowrap: bool = False,
77
77
  deterministic_spawn: bool = False,
78
+ teleport_interval: Optional[int] = None,
78
79
  ):
79
80
  super().__init__()
80
81
  self._name = name
@@ -87,6 +88,7 @@ class ForagaxEnv(environment.Environment):
87
88
  self.aperture_size = aperture_size
88
89
  self.nowrap = nowrap
89
90
  self.deterministic_spawn = deterministic_spawn
91
+ self.teleport_interval = teleport_interval
90
92
  objects = (EMPTY,) + objects
91
93
  if self.nowrap:
92
94
  objects = objects + (PADDING,)
@@ -117,6 +119,16 @@ class ForagaxEnv(environment.Environment):
117
119
  [b.stop if b.stop is not None else (-1, -1) for b in biomes]
118
120
  )
119
121
  self.biome_sizes = np.prod(self.biome_stops - self.biome_starts, axis=1)
122
+ self.biome_starts_jax = jnp.array(self.biome_starts)
123
+ self.biome_stops_jax = jnp.array(self.biome_stops)
124
+ biome_centers = []
125
+ for i in range(len(self.biome_starts)):
126
+ start = self.biome_starts[i]
127
+ stop = self.biome_stops[i]
128
+ center_x = (start[0] + stop[0] - 1) // 2
129
+ center_y = (start[1] + stop[1] - 1) // 2
130
+ biome_centers.append((center_x, center_y))
131
+ self.biome_centers_jax = jnp.array(biome_centers)
120
132
  self.biome_masks = []
121
133
  for i in range(self.biome_object_frequencies.shape[0]):
122
134
  # Create mask for the biome
@@ -174,6 +186,23 @@ class ForagaxEnv(environment.Environment):
174
186
  is_blocking = self.object_blocking[obj_at_new_pos]
175
187
  pos = jax.lax.select(is_blocking, state.pos, new_pos)
176
188
 
189
+ # Check for automatic teleport
190
+ if self.teleport_interval is not None:
191
+ should_teleport = jnp.mod(state.time + 1, self.teleport_interval) == 0
192
+ else:
193
+ should_teleport = False
194
+
195
+ def teleport_fn():
196
+ # Calculate squared distances from current position to each biome center
197
+ diffs = self.biome_centers_jax - pos
198
+ distances = jnp.sum(diffs**2, axis=1)
199
+ # Find the index of the furthest biome center
200
+ furthest_idx = jnp.argmax(distances)
201
+ new_pos = self.biome_centers_jax[furthest_idx]
202
+ return new_pos
203
+
204
+ pos = jax.lax.cond(should_teleport, teleport_fn, lambda: pos)
205
+
177
206
  # 2. HANDLE COLLISIONS AND REWARDS
178
207
  obj_at_pos = current_objects[pos[1], pos[0]]
179
208
  key, subkey = jax.random.split(key)
@@ -503,6 +532,7 @@ class ForagaxObjectEnv(ForagaxEnv):
503
532
  biomes: Tuple[Biome, ...] = (Biome(object_frequencies=()),),
504
533
  nowrap: bool = False,
505
534
  deterministic_spawn: bool = False,
535
+ teleport_interval: Optional[int] = None,
506
536
  ):
507
537
  super().__init__(
508
538
  name,
@@ -512,6 +542,7 @@ class ForagaxObjectEnv(ForagaxEnv):
512
542
  biomes,
513
543
  nowrap,
514
544
  deterministic_spawn,
545
+ teleport_interval,
515
546
  )
516
547
 
517
548
  # Compute unique colors and mapping for partial observability
@@ -318,6 +318,7 @@ def create_weather_objects(
318
318
  repeat: int = 500,
319
319
  multiplier: float = 1.0,
320
320
  same_color: bool = False,
321
+ random_respawn: bool = False,
321
322
  ):
322
323
  """Create HOT and COLD WeatherObject instances using the specified file.
323
324
 
@@ -346,6 +347,7 @@ def create_weather_objects(
346
347
  repeat=repeat,
347
348
  multiplier=multiplier,
348
349
  color=hot_color,
350
+ random_respawn=random_respawn,
349
351
  )
350
352
 
351
353
  cold_color = hot_color if same_color else (0, 255, 255)
@@ -355,6 +357,7 @@ def create_weather_objects(
355
357
  repeat=repeat,
356
358
  multiplier=-multiplier,
357
359
  color=cold_color,
360
+ random_respawn=random_respawn,
358
361
  )
359
362
 
360
363
  return hot, cold
@@ -64,6 +64,27 @@ ENV_CONFIGS: Dict[str, Dict[str, Any]] = {
64
64
  "biomes": None,
65
65
  "nowrap": True,
66
66
  },
67
+ "ForagaxWeather-v4": {
68
+ "size": None,
69
+ "aperture_size": None,
70
+ "objects": None,
71
+ "biomes": None,
72
+ "nowrap": True,
73
+ "deterministic_spawn": True,
74
+ },
75
+ "ForagaxWeather-v5": {
76
+ "size": (15, 15),
77
+ "aperture_size": None,
78
+ "objects": None,
79
+ "biomes": (
80
+ # Hot biome
81
+ Biome(start=(0, 3), stop=(15, 5), object_frequencies=(0.5, 0.0)),
82
+ # Cold biome
83
+ Biome(start=(0, 10), stop=(15, 12), object_frequencies=(0.0, 0.5)),
84
+ ),
85
+ "nowrap": False,
86
+ "deterministic_spawn": True,
87
+ },
67
88
  "ForagaxTwoBiome-v1": {
68
89
  "size": (15, 15),
69
90
  "aperture_size": None,
@@ -272,6 +293,19 @@ ENV_CONFIGS: Dict[str, Dict[str, Any]] = {
272
293
  "nowrap": True,
273
294
  "deterministic_spawn": True,
274
295
  },
296
+ "ForagaxTwoBiome-v16": {
297
+ "size": None,
298
+ "aperture_size": None,
299
+ "objects": (
300
+ BROWN_MOREL_UNIFORM_RANDOM,
301
+ BROWN_OYSTER_UNIFORM_RANDOM,
302
+ GREEN_DEATHCAP_UNIFORM_RANDOM,
303
+ GREEN_FAKE_UNIFORM_RANDOM,
304
+ ),
305
+ "biomes": None,
306
+ "nowrap": True,
307
+ "deterministic_spawn": True,
308
+ },
275
309
  "ForagaxTwoBiomeSmall-v1": {
276
310
  "size": (16, 8),
277
311
  "aperture_size": None,
@@ -348,6 +382,7 @@ def make(
348
382
  "ForagaxTwoBiome-v9",
349
383
  "ForagaxTwoBiome-v10",
350
384
  "ForagaxTwoBiome-v15",
385
+ "ForagaxTwoBiome-v16",
351
386
  ):
352
387
  margin = aperture_size[1] // 2 + 1
353
388
  width = 2 * margin + 9
@@ -386,7 +421,7 @@ def make(
386
421
  ),
387
422
  )
388
423
 
389
- if env_id == "ForagaxWeather-v3":
424
+ if env_id in ("ForagaxWeather-v3", "ForagaxWeather-v4"):
390
425
  margin = aperture_size[1] // 2 + 1
391
426
  width = 2 * margin + 9
392
427
  config["size"] = (15, width)
@@ -406,10 +441,21 @@ def make(
406
441
  )
407
442
 
408
443
  if env_id.startswith("ForagaxWeather"):
409
- same_color = env_id in ("ForagaxWeather-v2", "ForagaxWeather-v3")
410
- hot, cold = create_weather_objects(file_index=file_index, same_color=same_color)
444
+ same_color = env_id in (
445
+ "ForagaxWeather-v2",
446
+ "ForagaxWeather-v3",
447
+ "ForagaxWeather-v4",
448
+ "ForagaxWeather-v5",
449
+ )
450
+ random_respawn = env_id in ("ForagaxWeather-v4", "ForagaxWeather-v5")
451
+ hot, cold = create_weather_objects(
452
+ file_index=file_index, same_color=same_color, random_respawn=random_respawn
453
+ )
411
454
  config["objects"] = (hot, cold)
412
455
 
456
+ if env_id == "ForagaxTwoBiome-v16":
457
+ config["teleport_interval"] = 10000
458
+
413
459
  env_class_map = {
414
460
  "object": ForagaxObjectEnv,
415
461
  "rgb": ForagaxRGBEnv,
@@ -906,3 +906,62 @@ def test_single_color_all_objects():
906
906
  for i in range(3):
907
907
  obj_obs = obs[1, i, :] # Row 1, columns 0-2
908
908
  chex.assert_trees_all_equal(obj_obs, jnp.array([1.0]))
909
+
910
+
911
+ def test_teleporting():
912
+ """Test automatic teleporting to the furthest biome center from current position."""
913
+ key = jax.random.key(0)
914
+
915
+ # Create environment with two biomes and teleport every 5 steps
916
+ env = ForagaxObjectEnv(
917
+ size=(10, 10),
918
+ aperture_size=(3, 3),
919
+ objects=(WALL,),
920
+ biomes=(
921
+ Biome(
922
+ start=(1, 1), stop=(5, 5), object_frequencies=(0.0,)
923
+ ), # Biome 0 center at (2,2)
924
+ Biome(
925
+ start=(6, 6), stop=(10, 10), object_frequencies=(0.0,)
926
+ ), # Biome 1 center at (7,7)
927
+ ),
928
+ teleport_interval=5,
929
+ nowrap=True,
930
+ )
931
+ params = env.default_params
932
+
933
+ # Reset and get initial state
934
+ obs, state = env.reset_env(key, params)
935
+
936
+ # Agent should start at center (5, 5), which is not in either biome initially
937
+ # But let's manually place it in biome 0 for testing
938
+ state = state.replace(pos=jnp.array([2, 2])) # In biome 0
939
+
940
+ # Step 4 times (time will be 0,1,2,3,4 after these steps)
941
+ for i in range(4):
942
+ key, step_key = jax.random.split(key)
943
+ obs, state, _, _, _ = env.step_env(step_key, state, Actions.LEFT, params)
944
+
945
+ # After 4 steps, time=4, next step should teleport (4+1) % 5 == 0
946
+ key, step_key = jax.random.split(key)
947
+ obs, state, _, _, _ = env.step_env(step_key, state, Actions.LEFT, params)
948
+
949
+ # Should have teleported to the furthest biome center (biome 1 center)
950
+ # From (2,2), (7,7) is further than (2,2)
951
+ expected_pos = jnp.array([7, 7])
952
+ chex.assert_trees_all_equal(state.pos, expected_pos)
953
+
954
+ # Step another 4 times to reach time=9, then teleport back
955
+ # From [7,7], move right to stay in biome: [8,7], [9,7], then stay
956
+ for i in range(4):
957
+ key, step_key = jax.random.split(key)
958
+ obs, state, _, _, _ = env.step(step_key, state, Actions.RIGHT, params)
959
+
960
+ # After another 4 steps, time=9, next step should teleport (9+1) % 5 == 0
961
+ key, step_key = jax.random.split(key)
962
+ obs, state, _, _, _ = env.step(step_key, state, Actions.RIGHT, params)
963
+
964
+ # Should teleport to the furthest biome center (biome 0 center)
965
+ # From (7,7), (2,2) is further than (7,7)
966
+ expected_pos = jnp.array([2, 2])
967
+ chex.assert_trees_all_equal(state.pos, expected_pos)
@@ -0,0 +1,381 @@
1
+ import chex
2
+ import jax
3
+ import jax.numpy as jnp
4
+
5
+ from foragax.registry import make
6
+
7
+
8
+ def test_foragax_weather_v4_registry():
9
+ """Test that ForagaxWeather-v4 can be created via registry and has correct config."""
10
+ env = make("ForagaxWeather-v4", aperture_size=(5, 5))
11
+
12
+ # Check basic configuration
13
+ assert env.name == "ForagaxWeather-v4"
14
+ assert env.deterministic_spawn is True
15
+ assert env.nowrap is True
16
+
17
+ # Check that weather objects have random_respawn=True
18
+ hot, cold = env.objects[1], env.objects[2] # Skip EMPTY (index 0)
19
+ assert hot.name == "hot"
20
+ assert cold.name == "cold"
21
+ assert hot.random_respawn is True
22
+ assert cold.random_respawn is True
23
+
24
+ # Test basic functionality
25
+ key = jax.random.key(0)
26
+ obs, state = env.reset(key, env.default_params)
27
+ assert obs.shape == (5, 5, 2) # 2 color channels (hot/cold, padding)
28
+
29
+ # Test stepping
30
+ key, step_key = jax.random.split(key)
31
+ action = env.action_space(env.default_params).sample(step_key)
32
+ obs2, state2, reward, done, info = env.step(
33
+ step_key, state, action, env.default_params
34
+ )
35
+ assert obs2.shape == (5, 5, 2)
36
+ assert not done
37
+
38
+
39
+ def test_foragax_weather_v4_deterministic_spawn():
40
+ """Test that ForagaxWeather-v4 uses deterministic spawning."""
41
+ env = make("ForagaxWeather-v4", aperture_size=(5, 5))
42
+ params = env.default_params
43
+
44
+ # Test that multiple resets with same key produce same object placement
45
+ key = jax.random.key(42)
46
+ _, state1 = env.reset(key, params)
47
+
48
+ key = jax.random.key(42) # Same key
49
+ _, state2 = env.reset(key, params)
50
+
51
+ # Object grids should be identical (deterministic spawn)
52
+ chex.assert_trees_all_equal(state1.object_grid, state2.object_grid)
53
+
54
+ # But different keys should produce different placements
55
+ key1 = jax.random.key(42)
56
+ key2 = jax.random.key(43)
57
+ _, state1 = env.reset(key1, params)
58
+ _, state2 = env.reset(key2, params)
59
+
60
+ # Should be different (shuffled deterministically)
61
+ assert not jnp.array_equal(state1.object_grid, state2.object_grid)
62
+
63
+ # Test that number of objects is the same
64
+ num_hot_1 = jnp.sum(state1.object_grid == 1)
65
+ num_cold_1 = jnp.sum(state1.object_grid == 2)
66
+ num_hot_2 = jnp.sum(state2.object_grid == 1)
67
+ num_cold_2 = jnp.sum(state2.object_grid == 2)
68
+ assert num_hot_1 == num_hot_2
69
+ assert num_cold_1 == num_cold_2
70
+
71
+
72
+ def test_foragax_weather_v4_random_respawn():
73
+ """Test that ForagaxWeather-v4 weather objects have random_respawn=True."""
74
+ env = make("ForagaxWeather-v4", aperture_size=(5, 5))
75
+
76
+ # Check that weather objects have random_respawn=True
77
+ hot, cold = env.objects[1], env.objects[2] # Skip EMPTY
78
+ assert hot.random_respawn is True, "Hot objects should have random_respawn=True"
79
+ assert cold.random_respawn is True, "Cold objects should have random_respawn=True"
80
+
81
+ # Compare with v3
82
+ env_v3 = make("ForagaxWeather-v3", aperture_size=(5, 5))
83
+ hot_v3, cold_v3 = env_v3.objects[1], env_v3.objects[2]
84
+ assert hot_v3.random_respawn is False, (
85
+ "v3 hot objects should have random_respawn=False"
86
+ )
87
+ assert cold_v3.random_respawn is False, (
88
+ "v3 cold objects should have random_respawn=False"
89
+ )
90
+
91
+
92
+ def test_foragax_weather_v4_color_configuration():
93
+ """Test that ForagaxWeather-v4 weather objects use the same color."""
94
+ env = make("ForagaxWeather-v4", aperture_size=(5, 5))
95
+ hot_v4, cold_v4 = env.objects[1], env.objects[2]
96
+
97
+ # Same color configuration: v4 uses same color
98
+ assert hot_v4.color == cold_v4.color, "v4 should use same color for hot and cold"
99
+
100
+
101
+ def test_foragax_weather_v5_registry():
102
+ """Test that ForagaxWeather-v5 can be created via registry and has correct config."""
103
+ env = make("ForagaxWeather-v5", aperture_size=(5, 5))
104
+
105
+ # Check basic configuration
106
+ assert env.name == "ForagaxWeather-v5"
107
+ assert env.deterministic_spawn is True
108
+ assert env.nowrap is False # v5 enables wrapping
109
+
110
+ # Check that weather objects have random_respawn=True
111
+ hot, cold = env.objects[1], env.objects[2] # Skip EMPTY (index 0)
112
+ assert hot.name == "hot"
113
+ assert cold.name == "cold"
114
+ assert hot.random_respawn is True
115
+ assert cold.random_respawn is True
116
+
117
+ # Test basic functionality
118
+ key = jax.random.key(0)
119
+ obs, state = env.reset(key, env.default_params)
120
+ assert obs.shape == (5, 5, 1) # 1 color channel (hot/cold same color, no padding)
121
+
122
+ # Test stepping
123
+ key, step_key = jax.random.split(key)
124
+ action = env.action_space(env.default_params).sample(step_key)
125
+ obs2, state2, reward, done, info = env.step(
126
+ step_key, state, action, env.default_params
127
+ )
128
+ assert obs2.shape == (5, 5, 1)
129
+ assert not done
130
+
131
+
132
+ def test_foragax_weather_v5_deterministic_spawn():
133
+ """Test that ForagaxWeather-v5 uses deterministic spawning."""
134
+ env = make("ForagaxWeather-v5", aperture_size=(5, 5))
135
+ params = env.default_params
136
+
137
+ # Test that multiple resets with same key produce same object placement
138
+ key = jax.random.key(42)
139
+ _, state1 = env.reset(key, params)
140
+
141
+ key = jax.random.key(42) # Same key
142
+ _, state2 = env.reset(key, params)
143
+
144
+ # Object grids should be identical (deterministic spawn)
145
+ chex.assert_trees_all_equal(state1.object_grid, state2.object_grid)
146
+
147
+ # But different keys should produce different placements
148
+ key1 = jax.random.key(42)
149
+ key2 = jax.random.key(43)
150
+ _, state1 = env.reset(key1, params)
151
+ _, state2 = env.reset(key2, params)
152
+
153
+ # Should be different (shuffled deterministically)
154
+ assert not jnp.array_equal(state1.object_grid, state2.object_grid)
155
+
156
+ # Test that number of objects is the same
157
+ num_hot_1 = jnp.sum(state1.object_grid == 1)
158
+ num_cold_1 = jnp.sum(state1.object_grid == 2)
159
+ num_hot_2 = jnp.sum(state2.object_grid == 1)
160
+ num_cold_2 = jnp.sum(state2.object_grid == 2)
161
+ assert num_hot_1 == num_hot_2
162
+ assert num_cold_1 == num_cold_2
163
+
164
+
165
+ def test_foragax_weather_v5_random_respawn():
166
+ """Test that ForagaxWeather-v5 weather objects have random_respawn=True."""
167
+ env = make("ForagaxWeather-v5", aperture_size=(5, 5))
168
+
169
+ # Check that weather objects have random_respawn=True
170
+ hot, cold = env.objects[1], env.objects[2] # Skip EMPTY
171
+ assert hot.random_respawn is True, "Hot objects should have random_respawn=True"
172
+ assert cold.random_respawn is True, "Cold objects should have random_respawn=True"
173
+
174
+
175
+ def test_foragax_weather_v5_color_configuration():
176
+ """Test that ForagaxWeather-v5 weather objects use the same color."""
177
+ env = make("ForagaxWeather-v5", aperture_size=(5, 5))
178
+ hot_v5, cold_v5 = env.objects[1], env.objects[2]
179
+
180
+ # Same color configuration: v5 uses same color
181
+ assert hot_v5.color == cold_v5.color, "v5 should use same color for hot and cold"
182
+
183
+
184
+ def test_foragax_twobiome_v10_registry():
185
+ """Test that ForagaxTwoBiome-v10 can be created via registry and has correct config."""
186
+ env = make("ForagaxTwoBiome-v10", aperture_size=(5, 5))
187
+
188
+ # Check basic configuration
189
+ assert env.name == "ForagaxTwoBiome-v10"
190
+ assert env.deterministic_spawn is True
191
+ assert env.nowrap is True
192
+
193
+ # Check that objects have random_respawn=True
194
+ morel, oyster, deathcap, fake = (
195
+ env.objects[1],
196
+ env.objects[2],
197
+ env.objects[3],
198
+ env.objects[4],
199
+ ) # Skip EMPTY
200
+ assert morel.name == "brown_morel"
201
+ assert oyster.name == "brown_oyster"
202
+ assert deathcap.name == "green_deathcap"
203
+ assert fake.name == "green_fake"
204
+ assert morel.random_respawn is True
205
+ assert oyster.random_respawn is True
206
+ assert deathcap.random_respawn is True
207
+ assert fake.random_respawn is True
208
+
209
+ # Test basic functionality
210
+ key = jax.random.key(0)
211
+ obs, state = env.reset(key, env.default_params)
212
+ assert obs.shape == (5, 5, 3) # 3 color channels (brown, green, black padding)
213
+
214
+ # Test stepping
215
+ key, step_key = jax.random.split(key)
216
+ action = env.action_space(env.default_params).sample(step_key)
217
+ obs2, state2, reward, done, info = env.step(
218
+ step_key, state, action, env.default_params
219
+ )
220
+ assert obs2.shape == (5, 5, 3)
221
+ assert not done
222
+
223
+
224
+ def test_foragax_twobiome_v10_deterministic_spawn():
225
+ """Test that ForagaxTwoBiome-v10 uses deterministic spawning."""
226
+ env = make("ForagaxTwoBiome-v10", aperture_size=(5, 5))
227
+ params = env.default_params
228
+
229
+ # Test that multiple resets with same key produce same object placement
230
+ key = jax.random.key(42)
231
+ _, state1 = env.reset(key, params)
232
+
233
+ key = jax.random.key(42) # Same key
234
+ _, state2 = env.reset(key, params)
235
+
236
+ # Object grids should be identical (deterministic spawn)
237
+ chex.assert_trees_all_equal(state1.object_grid, state2.object_grid)
238
+
239
+ # But different keys should produce different placements
240
+ key1 = jax.random.key(42)
241
+ key2 = jax.random.key(43)
242
+ _, state1 = env.reset(key1, params)
243
+ _, state2 = env.reset(key2, params)
244
+
245
+ # Should be different (shuffled deterministically)
246
+ assert not jnp.array_equal(state1.object_grid, state2.object_grid)
247
+
248
+ # Test that number of objects is the same
249
+ num_morel_1 = jnp.sum(state1.object_grid == 1)
250
+ num_oyster_1 = jnp.sum(state1.object_grid == 2)
251
+ num_deathcap_1 = jnp.sum(state1.object_grid == 3)
252
+ num_fake_1 = jnp.sum(state1.object_grid == 4)
253
+ num_morel_2 = jnp.sum(state2.object_grid == 1)
254
+ num_oyster_2 = jnp.sum(state2.object_grid == 2)
255
+ num_deathcap_2 = jnp.sum(state2.object_grid == 3)
256
+ num_fake_2 = jnp.sum(state2.object_grid == 4)
257
+ assert num_morel_1 == num_morel_2
258
+ assert num_oyster_1 == num_oyster_2
259
+ assert num_deathcap_1 == num_deathcap_2
260
+ assert num_fake_1 == num_fake_2
261
+
262
+
263
+ def test_foragax_twobiome_v10_random_respawn():
264
+ """Test that ForagaxTwoBiome-v10 objects have random_respawn=True."""
265
+ env = make("ForagaxTwoBiome-v10", aperture_size=(5, 5))
266
+
267
+ # Check that all objects have random_respawn=True
268
+ morel, oyster, deathcap, fake = (
269
+ env.objects[1],
270
+ env.objects[2],
271
+ env.objects[3],
272
+ env.objects[4],
273
+ )
274
+ assert morel.random_respawn is True, "Morel objects should have random_respawn=True"
275
+ assert oyster.random_respawn is True, (
276
+ "Oyster objects should have random_respawn=True"
277
+ )
278
+ assert deathcap.random_respawn is True, (
279
+ "Deathcap objects should have random_respawn=True"
280
+ )
281
+ assert fake.random_respawn is True, "Fake objects should have random_respawn=True"
282
+
283
+
284
+ def test_foragax_twobiome_v13_registry():
285
+ """Test that ForagaxTwoBiome-v13 can be created via registry and has correct config."""
286
+ env = make("ForagaxTwoBiome-v13", aperture_size=(5, 5))
287
+
288
+ # Check basic configuration
289
+ assert env.name == "ForagaxTwoBiome-v13"
290
+ assert env.deterministic_spawn is True
291
+ assert env.nowrap is False
292
+
293
+ # Check that objects have random_respawn=True
294
+ morel, oyster, deathcap, fake = (
295
+ env.objects[1],
296
+ env.objects[2],
297
+ env.objects[3],
298
+ env.objects[4],
299
+ ) # Skip EMPTY
300
+ assert morel.name == "brown_morel"
301
+ assert oyster.name == "brown_oyster"
302
+ assert deathcap.name == "green_deathcap"
303
+ assert fake.name == "green_fake"
304
+ assert morel.random_respawn is True
305
+ assert oyster.random_respawn is True
306
+ assert deathcap.random_respawn is True
307
+ assert fake.random_respawn is True
308
+
309
+ # Test basic functionality
310
+ key = jax.random.key(0)
311
+ obs, state = env.reset(key, env.default_params)
312
+ assert obs.shape == (5, 5, 2) # 2 color channels (brown, green)
313
+
314
+ # Test stepping
315
+ key, step_key = jax.random.split(key)
316
+ action = env.action_space(env.default_params).sample(step_key)
317
+ obs2, state2, reward, done, info = env.step(
318
+ step_key, state, action, env.default_params
319
+ )
320
+ assert obs2.shape == (5, 5, 2)
321
+ assert not done
322
+
323
+
324
+ def test_foragax_twobiome_v13_deterministic_spawn():
325
+ """Test that ForagaxTwoBiome-v13 uses deterministic spawning."""
326
+ env = make("ForagaxTwoBiome-v13", aperture_size=(5, 5))
327
+ params = env.default_params
328
+
329
+ # Test that multiple resets with same key produce same object placement
330
+ key = jax.random.key(42)
331
+ _, state1 = env.reset(key, params)
332
+
333
+ key = jax.random.key(42) # Same key
334
+ _, state2 = env.reset(key, params)
335
+
336
+ # Object grids should be identical (deterministic spawn)
337
+ chex.assert_trees_all_equal(state1.object_grid, state2.object_grid)
338
+
339
+ # But different keys should produce different placements
340
+ key1 = jax.random.key(42)
341
+ key2 = jax.random.key(43)
342
+ _, state1 = env.reset(key1, params)
343
+ _, state2 = env.reset(key2, params)
344
+
345
+ # Should be different (shuffled deterministically)
346
+ assert not jnp.array_equal(state1.object_grid, state2.object_grid)
347
+
348
+ # Test that number of objects is the same
349
+ num_morel_1 = jnp.sum(state1.object_grid == 1)
350
+ num_oyster_1 = jnp.sum(state1.object_grid == 2)
351
+ num_deathcap_1 = jnp.sum(state1.object_grid == 3)
352
+ num_fake_1 = jnp.sum(state1.object_grid == 4)
353
+ num_morel_2 = jnp.sum(state2.object_grid == 1)
354
+ num_oyster_2 = jnp.sum(state2.object_grid == 2)
355
+ num_deathcap_2 = jnp.sum(state2.object_grid == 3)
356
+ num_fake_2 = jnp.sum(state2.object_grid == 4)
357
+ assert num_morel_1 == num_morel_2
358
+ assert num_oyster_1 == num_oyster_2
359
+ assert num_deathcap_1 == num_deathcap_2
360
+ assert num_fake_1 == num_fake_2
361
+
362
+
363
+ def test_foragax_twobiome_v13_random_respawn():
364
+ """Test that ForagaxTwoBiome-v13 objects have random_respawn=True."""
365
+ env = make("ForagaxTwoBiome-v13", aperture_size=(5, 5))
366
+
367
+ # Check that all objects have random_respawn=True
368
+ morel, oyster, deathcap, fake = (
369
+ env.objects[1],
370
+ env.objects[2],
371
+ env.objects[3],
372
+ env.objects[4],
373
+ )
374
+ assert morel.random_respawn is True, "Morel objects should have random_respawn=True"
375
+ assert oyster.random_respawn is True, (
376
+ "Oyster objects should have random_respawn=True"
377
+ )
378
+ assert deathcap.random_respawn is True, (
379
+ "Deathcap objects should have random_respawn=True"
380
+ )
381
+ assert fake.random_respawn is True, "Fake objects should have random_respawn=True"