diff --git a/src/game/main-urho3d.cc b/src/game/main-urho3d.cc
index befb718e5..785160736 100644
--- a/src/game/main-urho3d.cc
+++ b/src/game/main-urho3d.cc
@@ -713,7 +713,7 @@ void CryptoCityUrho3D::HandleBuy(StringHash eventType, VariantMap& eventData)
   cmd.buy.y = sy0;
   cmd.buy.wm1 = sx1 - sx0;
   cmd.buy.hm1 = sy1 - sy0;
-  if (map.command(cmd, tmp_n_players, tmp_players))
+  if (map.command(cmd, &playerState))
     cityMesh->buildMap();
 }
 
@@ -745,7 +745,7 @@ void CryptoCityUrho3D::HandleBuildOne(StringHash eventType, VariantMap& eventDat
   }
   cmd.push_area.type_ptr = encoded_types;
   cmd.push_area.type_len = encoded_types_len;
-  if (map.command(cmd, tmp_n_players, tmp_players))
+  if (map.command(cmd, &playerState))
     cityMesh->buildMap();
 }
 
@@ -764,7 +764,7 @@ void CryptoCityUrho3D::HandleDestroyOne(StringHash eventType, VariantMap& eventD
   cmd.push_area.dy = sy0 - flag->y0;
   cmd.push_area.wm1 = sx1 - sx0;
   cmd.push_area.hm1 = sy1 - sy0;
-  if (map.command(cmd, tmp_n_players, tmp_players))
+  if (map.command(cmd, &playerState))
     cityMesh->buildMap();
 }
 
diff --git a/src/game/map.cc b/src/game/map.cc
index 8a76bda47..2884e44bb 100644
--- a/src/game/map.cc
+++ b/src/game/map.cc
@@ -6,21 +6,12 @@
 #include <stdexcept>
 #include <algorithm>
 #include "get_us.h"
+#include "cc/cc.h"
 #include "cc/sqrtint.h"
 #include "map.h"
 
 using namespace Urho3D;
 
-#define STARTING_RADIUS 6
-#define BASE_TILE_BUY_COST 2
-#define BUY_BORDER_SIZE 2
-#define BASE_BLOCK_PLACEMENT_COST 100
-#define BLOCK_PLACEMENT_COST_INCREASE_RATE_INVERSE 1024
-#define BLOCK_POP_COST 0
-#define MIN_BUY_SIDE_SIZE 3
-#define EXPAND_SIZE 32
-#define NEW_FLAG_BASE_COST 99
-
 BlockMaterial materials[256] =
 {
   {
@@ -65,31 +56,6 @@ BlockMaterial materials[256] =
   },
 };
 
-Player tmp_players[] =
-{
-  { // the game itself
-    0,
-    0,
-    "",
-#define I (uint32_t)-1
-    {I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, },
-#undef I
-  },
-  {
-    1,
-    1234567,
-    "test player 1",
-    {0, 1000, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
-  },
-  {
-    2,
-    1000,
-    "test player 2",
-    {0, 80, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
-  },
-};
-size_t tmp_n_players = sizeof(tmp_players) / sizeof(tmp_players[0]);
-
 bool encode_single_type(uint8_t src_type, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len)
 {
   *encoded_types_len = 0;
@@ -103,100 +69,6 @@ bool encode_single_type(uint8_t src_type, uint16_t n_src_types, uint8_t *encoded
   return true;
 }
 
-bool encode_types(const uint8_t *src_types, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len)
-{
-  *encoded_types_len = 0;
-  while (n_src_types > 0)
-  {
-    // find offset of next run > 2
-    uint8_t offset = 0;
-    bool found = false;
-    while (offset + 2 < n_src_types && offset < 127 - 1)
-    {
-      const uint8_t *ptr = src_types + offset;
-      if (*ptr == *(ptr+1) && *ptr == *(ptr+2))
-      {
-        found = true;
-        break;
-      }
-      ++offset;
-    }
-//printf("offset %u, found %d, n_src_types %u\n", offset, found, n_src_types);
-    if (!found && offset == 0)
-    {
-      if (n_src_types > 2)
-      {
-        printf("Bug: found %d, n_src_types %u, offset %u\n", found, n_src_types, offset);
-        return false;
-      }
-      offset = n_src_types;
-    }
-    if (offset > 0)
-    {
-      uint8_t len = offset;
-      if (*encoded_types_len >= 65535 - 1 - len)
-        return false;
-//printf("encoding %u list strip\n", len);
-      encoded_types[++*encoded_types_len - 1] = 0x00 | len;
-      n_src_types -= len;
-      while (len--)
-        encoded_types[++*encoded_types_len - 1] = *src_types++;
-    }
-    if (found)
-    {
-      // work out next run length
-      uint8_t len = 1;
-      while (len < 127 && n_src_types > len && src_types[len] == src_types[0])
-        ++len;
-//printf("encoding %u rle strip\n", len);
-      if (*encoded_types_len >= 65535 - 2)
-        return false;
-      encoded_types[++*encoded_types_len - 1] = 0x80 | len;
-      encoded_types[++*encoded_types_len - 1] = src_types[0];
-      n_src_types -= len;
-      src_types += len;
-    }
-  }
-  return true;
-}
-
-bool decode_types(const uint8_t *encoded_types, uint16_t encoded_types_len, uint8_t *dst_types, uint16_t *n_dst_types)
-{
-  *n_dst_types = 0;
-  while (encoded_types_len-- > 0)
-  {
-    const bool is_rle = (*encoded_types) & 0x80;
-    uint8_t len = (*encoded_types) & 0x7f;
-    ++encoded_types;
-    if (is_rle)
-    {
-      if (encoded_types_len < 1)
-        return false;
-      uint8_t t = *encoded_types++;
-      encoded_types_len--;
-      if (*n_dst_types >= 65535 - len)
-        return false;
-      while (len--)
-        dst_types[++*n_dst_types - 1] = t;
-    }
-    else
-    {
-      if (encoded_types_len < len)
-        goto error;
-      encoded_types_len -= len;
-      if (*n_dst_types >= 65535 - len)
-        return false;
-      while (len--)
-        dst_types[++*n_dst_types - 1] = *encoded_types++;
-    }
-  }
-  return true;
-
-error:
-  *n_dst_types = 0;
-  return false;
-}
-
 void Tile::push(uint8_t type)
 {
   if (height == std::numeric_limits<uint16_t>::max())
@@ -387,7 +259,7 @@ bool Flag::check_build_rules(const Tile &t, uint32_t x, uint32_t y, uint16_t hei
   return true;
 }
 
-bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len)
+bool Flag::push_tiles(PlayerState *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len)
 {
   if (px0 < x0 || px1 > x1 || py0 < y0 || py1 > y1)
   {
@@ -396,8 +268,8 @@ bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1,
   }
 
   uint8_t decoded_types[65536];
-  uint16_t n_decoded_types;
-  if (!decode_types(type_ptr, type_len, decoded_types, &n_decoded_types))
+  uint32_t n_decoded_types;
+  if (!cc::decode_blocks(type_ptr, type_len, decoded_types, &n_decoded_types))
   {
     printf("Failed to decode types\n");
     return false;
@@ -413,7 +285,7 @@ bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1,
   uint64_t cost = 0;
   const uint32_t w = x1 - x0 + 1;
   uint32_t done = 0;
-  const uint32_t owner = player->owner;
+  const uint32_t owner = player->id;
   uint32_t blocks_needed[256] = {0};
   for (uint32_t ty = py0; ty <= py1; ++ty)
   {
@@ -440,9 +312,9 @@ bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1,
   }
   for (uint32_t idx = 1; idx < 256; ++idx)
   {
-    if (blocks_needed[idx] > player->blocks[idx])
+    if (blocks_needed[idx] > player->block_balances[idx])
     {
-      printf("Not enough blocks of type %u (%u, needs %u)\n", idx, player->blocks[idx], blocks_needed[idx]);
+      printf("Not enough blocks of type %u (%u, needs %u)\n", idx, player->block_balances[idx], blocks_needed[idx]);
       goto undo;
     }
   }
@@ -459,7 +331,7 @@ bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1,
 
   player->balance -= cost;
   for (uint32_t idx = 1; idx < 256; ++idx)
-    player->blocks[idx] -= blocks_needed[idx];
+    player->block_balances[idx] -= blocks_needed[idx];
 
   return true;
 
@@ -481,7 +353,7 @@ undo:
   return false;
 }
 
-bool Flag::pop_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1)
+bool Flag::pop_tiles(PlayerState *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1)
 {
   if (px0 < x0 || px1 > x1 || py0 < y0 || py1 > y1)
   {
@@ -610,14 +482,6 @@ bool Flag::build_predefined(const char *name, uint32_t bx0, uint32_t by0, uint32
   return true;
 }
 
-void TopOfTheWorld::reset()
-{
-  tallest.owner = 0;
-  tallest.x = 0;
-  tallest.y = 0;
-  tallest.height = 0;
-}
-
 Map::Map(uint32_t x, uint32_t y): ox(x), oy(y)
 {
   if (x == std::numeric_limits<uint32_t>::max())
@@ -693,9 +557,9 @@ void Map::get_flags(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, std::deq
   qflags.query(x0, y0, x1, y1, res);
 }
 
-bool Map::buy(Player *player, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1)
+bool Map::buy(PlayerState *player, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1)
 {
-  if (!player || !player->owner)
+  if (!player || !player->id)
   {
     printf("Bad player");
     return false;
@@ -706,7 +570,7 @@ bool Map::buy(Player *player, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1)
     return false;
   }
 
-  const uint32_t owner = player->owner;
+  const uint32_t owner = player->id;
   if (has_flag(x, y, x+wm1, y+hm1))
   {
     printf("Already owned\n");
@@ -740,15 +604,15 @@ bool Map::buy(Player *player, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1)
   return true;
 }
 
-bool Map::push_tiles(Player *player, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len)
+bool Map::push_tiles(PlayerState *player, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len)
 {
-  if (!player || !player->owner)
+  if (!player || !player->id)
   {
     printf("Bad player");
     return false;
   }
   SharedPtr<Flag> flag = get_flag(flag_id);
-  if (!flag || flag->owner != player->owner)
+  if (!flag || flag->owner != player->id)
   {
     printf("Not owned\n");
     return false;
@@ -756,15 +620,15 @@ bool Map::push_tiles(Player *player, uint32_t flag_id, uint8_t dx, uint8_t dy, u
   return flag->push_tiles(player, flag->x0 + dx, flag->y0 + dy, flag->x0 + dx + wm1, flag->y0 + dy + hm1, min_height, type_ptr, type_len);
 }
 
-bool Map::pop_tiles(Player *player, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1)
+bool Map::pop_tiles(PlayerState *player, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1)
 {
-  if (!player || !player->owner)
+  if (!player || !player->id)
   {
     printf("Bad player");
     return false;
   }
   SharedPtr<Flag> flag = get_flag(flag_id);
-  if (!flag || flag->owner != player->owner)
+  if (!flag || flag->owner != player->id)
   {
     printf("Not owned\n");
     return false;
@@ -772,15 +636,14 @@ bool Map::pop_tiles(Player *player, uint32_t flag_id, uint8_t dx, uint8_t dy, ui
   return flag->pop_tiles(player, flag->x0 + dx, flag->y0 + dy, flag->x0 + dx + wm1, flag->y0 + dy + hm1);
 }
 
-bool Map::command(const Command &cmd, size_t n_players, Player *players)
+bool Map::command(const Command &cmd, PlayerState *player)
 {
-  if (cmd.owner == 0 || cmd.owner >= n_players)
+  if (!player || player->id == 0)
   {
     printf("Invalid player\n");
     return false;
   }
-  Player *player = players + cmd.owner;
-  if (player->owner != cmd.owner)
+  if (player->id != cmd.owner)
   {
     printf("Inconsistent player\n");
     return false;
@@ -831,95 +694,3 @@ bool Map::build_predefined(const char *name, uint32_t bx0, uint32_t by0, uint32_
   }
   return flag->build_predefined(name, bx0, by0, bx1, by1);
 }
-
-void Map::get_top_of_the_world(TopOfTheWorld &totw) const
-{
-#if 0
-  totw.reset();
-
-  const uint32_t w = x1 - x0 + 1;
-  for (uint32_t y = y0; y <= y1; ++y)
-  {
-    for (uint32_t x = x0; x <= x1; ++x)
-    {
-      const Tile &t = tiles[(y-y0) * w + x-x0];
-      uint32_t owner = t.get_owner();
-      if (owner != 0)
-      {
-        const uint16_t th = t.get_height();
-        if (th > totw.tallest.height)
-        {
-          totw.tallest.owner = owner;
-          totw.tallest.x = x;
-          totw.tallest.y = y;
-          totw.tallest.height = th;
-        }
-      }
-    }
-  }
-#endif
-}
-
-void Map::test_encoding(unsigned int seed)
-{
-  uint8_t raw[65536], encoded[65536], decoded[65536];
-  uint16_t encoded_len, decoded_len;
-  if (seed == 0)
-    seed = time(NULL);
-//seed = 1563281381;
-  srand(seed);
-  uint64_t total = 0, bytes = 0;
-
-  const unsigned int n_recover_tests = 100;
-  const unsigned int n_decode_tests = 10000;
-
-  for (unsigned int i = 0; i < n_recover_tests; ++i)
-  {
-    uint16_t len = rand();
-    for (int n = 0; n < len; ++n)
-    {
-      raw[n] = rand() & 7;
-    }
-    if (!encode_types(raw, len, encoded, &encoded_len))
-    {
-      printf("Failed to encode: seed %u, input len %u\n", seed, len);
-      continue;
-    }
-    if (!decode_types(encoded, encoded_len, decoded, &decoded_len))
-    {
-      printf("Failed to decode: seed %u\n", seed);
-      return;
-    }
-    if (decoded_len != len)
-    {
-      printf("Decoded len is wrong: seed %u\n", seed);
-      return;
-    }
-    if (memcmp(raw, decoded, len))
-    {
-      printf("Decoded data is wrong: seed %u\n", seed);
-      return;
-    }
-    if (encoded_len > len)
-    {
-      //printf("encoded_len (%u) > len (%u): seed %u: %.3f\n", encoded_len, len, seed, 100.0f * encoded_len / (float)len);
-    }
-    printf("\r%u/%u    ", i, n_recover_tests); fflush(stdout);
-    total += len;
-    bytes += encoded_len;
-  }
-  printf("\r                 \r\n");
-  printf("Compression: %.3f%%\n", 100.0f * bytes/(float)total);
-
-  for (unsigned int i = 0; i < n_decode_tests; ++i)
-  {
-    uint16_t len = rand();
-    for (int n = 0; n < len; ++n)
-    {
-      raw[n] = rand();
-    }
-    decode_types(raw, len, decoded, &decoded_len);
-    printf("\r%u/%u    ", i, n_decode_tests); fflush(stdout);
-  }
-  printf("\r                 \r\n");
-}
diff --git a/src/game/map.h b/src/game/map.h
index ca068bd0c..380f12668 100644
--- a/src/game/map.h
+++ b/src/game/map.h
@@ -6,19 +6,9 @@
 #include <map>
 #include <Urho3D/Container/RefCounted.h>
 #include <Urho3D/Container/Ptr.h>
+#include "player-state.h"
 #include "quadtree.h"
 
-struct Player
-{
-  uint32_t owner;
-  uint64_t balance;
-  const char *name;
-  uint32_t blocks[256];
-};
-
-extern Player tmp_players[];
-extern size_t tmp_n_players;
-
 struct BlockMaterial
 {
   uint8_t type;
@@ -41,8 +31,6 @@ struct BlockMaterial
 extern BlockMaterial materials[256];
 
 bool encode_single_type(uint8_t src_type, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len);
-bool encode_types(const uint8_t *src_types, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len);
-bool decode_types(const uint8_t *encoded_types, uint16_t encoded_types_len, uint8_t *dst_types, uint16_t *n_dst_types);
 
 class Tile
 {
@@ -91,8 +79,8 @@ public:
   uint64_t get_block_cost_for_height(uint16_t h) const;
   uint16_t get_tile_height(uint32_t x, uint32_t y) const;
 
-  bool push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len);
-  bool pop_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1);
+  bool push_tiles(PlayerState *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len);
+  bool pop_tiles(PlayerState *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1);
 
   bool build_predefined(const char *name, uint32_t bx0, uint32_t by0, uint32_t bx1, uint32_t by1);
 
@@ -152,21 +140,6 @@ struct Command
   };
 };
 
-struct TopOfTheWorld
-{
-  struct Tallest
-  {
-    uint32_t owner;
-    uint32_t x;
-    uint32_t y;
-    uint16_t height;
-  };
-  Tallest tallest;
-
-  TopOfTheWorld() { reset(); }
-  void reset();
-};
-
 struct Map
 {
   Map(uint32_t x, uint32_t y);
@@ -184,11 +157,10 @@ struct Map
   bool build_predefined(const char *name, uint32_t bx0, uint32_t by0, uint32_t bx1, uint32_t by1);
 
   // consensus
-  bool buy(Player *p, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1);
-  bool push_tiles(Player *p, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len);
-  bool pop_tiles(Player *p, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1);
-  bool command(const Command &cmd, size_t nplayers, Player *players);
-  void get_top_of_the_world(TopOfTheWorld &totw) const;
+  bool buy(PlayerState *p, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1);
+  bool push_tiles(PlayerState *p, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len);
+  bool pop_tiles(PlayerState *p, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1);
+  bool command(const Command &cmd, PlayerState *player);
 
 private:
   uint32_t allocate_new_flag();