@@ -66,6 +66,10 @@ using Rgb = std::array<std::uint8_t, 3>;
6666
6767inline constexpr int kTilePixels = 32 ;
6868inline constexpr int kTileSubdivs = 3 ;
69+ inline constexpr int kMatrixAgentChannel = 5 ;
70+ inline constexpr int kMatrixColorChannel = 6 ;
71+ inline constexpr int kMatrixDirectionChannel = 9 ;
72+ inline constexpr int kMatrixObsChannels = 13 ;
6973inline constexpr double kPi = 3.14159265358979323846 ;
7074inline constexpr Rgb kShadowColor = {35 , 25 , 30 };
7175inline constexpr Rgb kWorstColor = {74 , 65 , 42 };
@@ -376,15 +380,32 @@ class MarlGridEnvFns {
376380 " reset_on_mistake" _.Bind (false ), " reward_decay" _.Bind (true ),
377381 " respawn" _.Bind (false ), " ghost_mode" _.Bind (true ),
378382 " prestige_coloring" _.Bind (false ),
379- " prestige_beta" _.Bind (0 .95f ), " prestige_scale" _.Bind (2 .0f ));
383+ " prestige_beta" _.Bind (0 .95f ), " prestige_scale" _.Bind (2 .0f ),
384+ " observation_format" _.Bind (std::string (" pixels" )));
380385 }
381386
382387 template <typename Config>
383388 static decltype (auto ) StateSpec(const Config& conf) {
389+ const std::string observation_format = conf[" observation_format" _];
390+ if (observation_format != " pixels" && observation_format != " matrix" &&
391+ observation_format != " full_matrix" ) {
392+ throw std::runtime_error (
393+ " MarlGrid observation_format must be 'pixels', 'matrix', or "
394+ " 'full_matrix'" );
395+ }
384396 int obs_size = conf[" view_size" _] * conf[" view_tile_size" _];
397+ int obs_channels = 3 ;
398+ if (observation_format == " matrix" ) {
399+ obs_size = conf[" view_size" _];
400+ obs_channels = detail::kMatrixObsChannels ;
401+ } else if (observation_format == " full_matrix" ) {
402+ obs_size = conf[" grid_size" _];
403+ obs_channels = detail::kMatrixObsChannels ;
404+ }
385405 int bound = conf[" grid_size" _];
386406 return MakeDict (
387- " obs" _.Bind (Spec<std::uint8_t >({-1 , obs_size, obs_size, 3 }, {0 , 255 })),
407+ " obs" _.Bind (Spec<std::uint8_t >({-1 , obs_size, obs_size, obs_channels},
408+ {0 , 255 })),
388409 " info:players.id" _.Bind (Spec<int >({-1 }, {0 , conf[" max_num_players" _]})),
389410 " info:players.done" _.Bind (Spec<bool >({-1 })),
390411 " info:players.active" _.Bind (Spec<bool >({-1 })),
@@ -423,6 +444,7 @@ class MarlGridEnv : public Env<MarlGridEnvSpec>, public RenderableEnv {
423444 prestige_coloring_ (spec.config[" prestige_coloring" _]),
424445 prestige_beta_ (spec.config[" prestige_beta" _]),
425446 prestige_scale_ (spec.config[" prestige_scale" _]),
447+ observation_format_ (spec.config[" observation_format" _]),
426448 max_episode_steps_ (spec.config[" max_episode_steps" _]) {
427449 CHECK_GE (max_num_players_, n_agents_);
428450 CHECK_GE (grid_size_, 3 );
@@ -546,6 +568,7 @@ class MarlGridEnv : public Env<MarlGridEnvSpec>, public RenderableEnv {
546568 bool prestige_coloring_{false };
547569 float prestige_beta_{0 .95f };
548570 float prestige_scale_{2 .0f };
571+ std::string observation_format_{" pixels" };
549572 int max_episode_steps_{100 };
550573 int step_count_{0 };
551574 bool done_{true };
@@ -844,25 +867,29 @@ class MarlGridEnv : public Env<MarlGridEnvSpec>, public RenderableEnv {
844867 return detail::RenderAgentTile (agent.color , agent.dir , tile_size);
845868 }
846869
870+ [[nodiscard]] int TopAgentForCell (const detail::Cell* cell,
871+ int top_agent_id) const {
872+ if (cell == nullptr ) {
873+ return -1 ;
874+ }
875+ if (top_agent_id >= 0 &&
876+ std::find (cell->agents .begin (), cell->agents .end (), top_agent_id) !=
877+ cell->agents .end () &&
878+ agents_[top_agent_id].active ) {
879+ return top_agent_id;
880+ }
881+ for (int agent_id : cell->agents ) {
882+ if (agents_[agent_id].active ) {
883+ return agent_id;
884+ }
885+ }
886+ return -1 ;
887+ }
888+
847889 [[nodiscard]] std::vector<std::uint8_t > RenderTile (const detail::Cell* cell,
848890 int top_agent_id,
849891 int tile_size) const {
850- int chosen_agent = -1 ;
851- if (cell != nullptr ) {
852- if (top_agent_id >= 0 &&
853- std::find (cell->agents .begin (), cell->agents .end (), top_agent_id) !=
854- cell->agents .end () &&
855- agents_[top_agent_id].active ) {
856- chosen_agent = top_agent_id;
857- } else {
858- for (int agent_id : cell->agents ) {
859- if (agents_[agent_id].active ) {
860- chosen_agent = agent_id;
861- break ;
862- }
863- }
864- }
865- }
892+ int chosen_agent = TopAgentForCell (cell, top_agent_id);
866893 if (cell == nullptr || cell->type == detail::CellType::kEmpty ) {
867894 if (chosen_agent >= 0 ) {
868895 auto tile = RenderAgentTile (chosen_agent, tile_size);
@@ -900,38 +927,41 @@ class MarlGridEnv : public Env<MarlGridEnvSpec>, public RenderableEnv {
900927 }
901928 }
902929
903- void RenderAgentObs (int agent_id, std::uint8_t * output) const {
904- int obs_size = view_size_ * view_tile_size_;
905- std::vector<std::uint8_t > image (obs_size * obs_size * 3 , 0 );
906- for (int i = 0 ; i < obs_size * obs_size; ++i) {
907- image[i * 3 + 0 ] = detail::kShadowColor [0 ];
908- image[i * 3 + 1 ] = detail::kShadowColor [1 ];
909- image[i * 3 + 2 ] = detail::kShadowColor [2 ];
910- }
911- const detail::Agent& agent = agents_[agent_id];
912- if (!agent.active ) {
913- std::memcpy (output, image.data (), image.size ());
914- return ;
915- }
930+ [[nodiscard]] auto AgentViewCells (const detail::Agent& agent) const {
916931 int rot_k = (agent.dir + 1 ) % 4 ;
917- int orientation = (4 - rot_k) % 4 ;
918932 auto [top_x, top_y] = ViewTopLeft (agent);
919- std::vector<const detail::Cell*> view_cells (view_size_ * view_size_,
920- nullptr );
921- std::vector<bool > transparent (view_size_ * view_size_, true );
933+ std::vector<const detail::Cell*> cells (view_size_ * view_size_, nullptr );
934+ std::vector<bool > transparent (cells.size (), true );
922935 for (int y = 0 ; y < view_size_; ++y) {
923936 for (int x = 0 ; x < view_size_; ++x) {
924937 auto [sx, sy] = detail::RotateCoord (x, y, view_size_, rot_k);
925938 int wx = top_x + sx;
926939 int wy = top_y + sy;
927940 if (InBounds (wx, wy)) {
928941 const detail::Cell& cell = CellAt (wx, wy);
929- view_cells [detail::Offset (x, y, view_size_)] = &cell;
942+ cells [detail::Offset (x, y, view_size_)] = &cell;
930943 transparent[detail::Offset (x, y, view_size_)] = cell.CanSeeBehind ();
931944 }
932945 }
933946 }
934- std::vector<bool > visible = VisibilityMask (transparent);
947+ return std::pair{std::move (cells), VisibilityMask (transparent)};
948+ }
949+
950+ void RenderAgentObs (int agent_id, std::uint8_t * output) const {
951+ int obs_size = view_size_ * view_tile_size_;
952+ std::vector<std::uint8_t > image (obs_size * obs_size * 3 , 0 );
953+ for (int i = 0 ; i < obs_size * obs_size; ++i) {
954+ image[i * 3 + 0 ] = detail::kShadowColor [0 ];
955+ image[i * 3 + 1 ] = detail::kShadowColor [1 ];
956+ image[i * 3 + 2 ] = detail::kShadowColor [2 ];
957+ }
958+ const detail::Agent& agent = agents_[agent_id];
959+ if (!agent.active ) {
960+ std::memcpy (output, image.data (), image.size ());
961+ return ;
962+ }
963+ int orientation = 3 - agent.dir ;
964+ auto [view_cells, visible] = AgentViewCells (agent);
935965 for (int y = 0 ; y < view_size_; ++y) {
936966 for (int x = 0 ; x < view_size_; ++x) {
937967 if (!visible[detail::Offset (x, y, view_size_)]) {
@@ -953,6 +983,73 @@ class MarlGridEnv : public Env<MarlGridEnvSpec>, public RenderableEnv {
953983 std::memcpy (output, image.data (), image.size ());
954984 }
955985
986+ static int MatrixObsOffset (int x, int y, int channel, int obs_size) {
987+ return (y * obs_size + x) * detail::kMatrixObsChannels + channel;
988+ }
989+
990+ void WriteMatrixBaseTile (const detail::Cell* cell, int x, int y, int obs_size,
991+ std::uint8_t * output) const {
992+ int base_channel = cell == nullptr ? 0 : static_cast <int >(cell->type );
993+ output[MatrixObsOffset (x, y, base_channel, obs_size)] = 255 ;
994+ }
995+
996+ void WriteMatrixAgentTile (int chosen_agent, int x, int y, int obs_size,
997+ int orientation, std::uint8_t * output) const {
998+ if (chosen_agent < 0 ) {
999+ return ;
1000+ }
1001+ detail::Rgb color =
1002+ prestige_coloring_
1003+ ? detail::PrestigeColor (agents_[chosen_agent].prestige ,
1004+ prestige_scale_)
1005+ : detail::ColorValue (agents_[chosen_agent].color );
1006+ output[MatrixObsOffset (x, y, detail::kMatrixAgentChannel , obs_size)] = 255 ;
1007+ std::copy (
1008+ color.begin (), color.end (),
1009+ output + MatrixObsOffset (x, y, detail::kMatrixColorChannel , obs_size));
1010+ int direction = (agents_[chosen_agent].dir + orientation) % 4 ;
1011+ output[MatrixObsOffset (x, y, detail::kMatrixDirectionChannel + direction,
1012+ obs_size)] = 255 ;
1013+ }
1014+
1015+ void WriteAgentMatrixObs (int agent_id, std::uint8_t * output) const {
1016+ int obs_values = view_size_ * view_size_ * detail::kMatrixObsChannels ;
1017+ std::fill (output, output + obs_values, 0 );
1018+ const detail::Agent& agent = agents_[agent_id];
1019+ if (!agent.active ) {
1020+ return ;
1021+ }
1022+ int orientation = 3 - agent.dir ;
1023+ auto [view_cells, visible] = AgentViewCells (agent);
1024+ for (int y = 0 ; y < view_size_; ++y) {
1025+ for (int x = 0 ; x < view_size_; ++x) {
1026+ if (!visible[detail::Offset (x, y, view_size_)]) {
1027+ continue ;
1028+ }
1029+ const detail::Cell* cell = view_cells[detail::Offset (x, y, view_size_)];
1030+ WriteMatrixBaseTile (cell, x, y, view_size_, output);
1031+ WriteMatrixAgentTile (TopAgentForCell (cell, agent_id), x, y, view_size_,
1032+ orientation, output);
1033+ }
1034+ }
1035+ }
1036+
1037+ void WriteAgentFullMatrixObs (int agent_id, std::uint8_t * output) const {
1038+ int obs_values = grid_size_ * grid_size_ * detail::kMatrixObsChannels ;
1039+ std::fill (output, output + obs_values, 0 );
1040+ if (!agents_[agent_id].active ) {
1041+ return ;
1042+ }
1043+ for (int y = 0 ; y < grid_size_; ++y) {
1044+ for (int x = 0 ; x < grid_size_; ++x) {
1045+ const detail::Cell& cell = CellAt (x, y);
1046+ WriteMatrixBaseTile (&cell, x, y, grid_size_, output);
1047+ WriteMatrixAgentTile (TopAgentForCell (&cell, agent_id), x, y, grid_size_,
1048+ 0 , output);
1049+ }
1050+ }
1051+ }
1052+
9561053 void ResizeNearest (const std::uint8_t * src, int src_width, int src_height,
9571054 std::uint8_t * dst, int dst_width, int dst_height) const {
9581055 for (int y = 0 ; y < dst_height; ++y) {
@@ -975,7 +1072,14 @@ class MarlGridEnv : public Env<MarlGridEnvSpec>, public RenderableEnv {
9751072 state[" info:players.pos" _](i, 1 ) = agents_[i].y ;
9761073 state[" info:players.dir" _][i] = agents_[i].dir ;
9771074 state[" reward" _][i] = last_rewards_[i];
978- RenderAgentObs (i, static_cast <std::uint8_t *>(state[" obs" _][i].Data ()));
1075+ auto * obs = static_cast <std::uint8_t *>(state[" obs" _][i].Data ());
1076+ if (observation_format_ == " matrix" ) {
1077+ WriteAgentMatrixObs (i, obs);
1078+ } else if (observation_format_ == " full_matrix" ) {
1079+ WriteAgentFullMatrixObs (i, obs);
1080+ } else {
1081+ RenderAgentObs (i, obs);
1082+ }
9791083 }
9801084 }
9811085};
0 commit comments