Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - Yves

Pages: [1]
1
General Discussion / Anyone went below the green acid?
« on: February 27, 2019, 07:18:47 pm »
Using my automatic digging robot, I reached the layer just above the green acid.

Then I dug some more, and saw that I could not reach the acid layer, nor could I have access to any “hanging thing” to go down. Nevertheless, I was able to reach the acid itself by dropping loads of rolling voxels until I could reach them.

However, the rolling voxels seem to float on the acid instead of drowning, so I’m back to the initial problem: I’m standing of my raft of rolling voxels, but still unable to attach voxels to anything below, for the lack of anything reachable.

“Why?”, will you say… I don’t know. I just want to explore :-) And the challenge, too.

So, anyone managed to go below the green acid without bypassing it through another zone?

2
Programming with Blackvoxel / Programmatic handling of the player
« on: February 27, 2019, 07:08:48 pm »
I was pondering the creation of a program to move the player faster, more specifically an elevator, because going down/up stairs is so slow!

I had the feeling that the answer was in PlayerAddAccel or PlayerSetAccel. But playing with one only made the game more/less smooth, and playing with the other either 1º moved me of a few pixels, or 2º moved me a dozen voxels in the air, and then I died falling.

I was not able to understand either of these functions by trial-and-error… Is there a better explanation of these functions somewhere?

3
Programming with Blackvoxel / Digging and sorting robot
« on: February 26, 2019, 11:43:38 pm »
Hello,
Here I share the program I wrote to automatically dig, and place all that was taken in the appropriate storages.

This is still a bit rough around the edges, because I did not mind too much having to interfere with the robots once in a while instead of just fixing the program :-D
For example:
— Two robots can block themselves when they are front-to-front. Just alter the stock sequence of the robot that is going towards a storage, and it will go away.
— The robots expect a free path towards the storages, which actually depends on the position of the digging zones, relative to the factory zone.

Enough “talk”, here’s the code:
Code: [Select]
// Tunnel 16x16 downward
// *******************************************************************

const SOFT_LIMIT = 50;
const HARD_LIMIT = 1323;
const QUARTER_SIZE = 8;
const KEY_LEARN = 108;    // L (https://wiki.libsdl.org/SDLKeycodeLookup)
const KEY_VALIDATE = 111; // O (https://wiki.libsdl.org/SDLKeycodeLookup)
const KEY_CANCEL = 113;   // Q (https://wiki.libsdl.org/SDLKeycodeLookup)

const ST_END = 0;
const ST_INIT = 10;
const ST_CENTER = 20;
const ST_QUARTER = 30;
const ST_ASIDE = 40;
const ST_CLIMB = 50;
const ST_RETURN = 60;
const ST_DOCK = 70;
const ST_TRANSPORT = 80;
const ST_LEARN = 90;
const ST_UNLOAD = 100;
const ST_NEXTVOXEL = 110;

const WAIT = 2000;
Time <- 0;

InitDir <- 0;
State <- 0;
StartX <- 0;
StartY <- 0;
StartZ <- 0;
CenterX <- 0;
CenterZ <- 0;
StepX <- 0;
StepZ <- 0;
StepXBeforeZ <- true;
FlatSteps <- 0;
Dir <- 0;
Depth <- 0;
Quarter <- 0;
CellCount <- 0;
RowCount <- 0;
StartStock <- 0;
UnloadType <- 0;
UnloadXYZ <- {};
HardLimitReached <- false;

// This function is called at each robot cycle.

function Voxel_Step()
{
  local ok = true;
  local slot;
  local x;
  local y;
  local z;

  switch ( State )
  {
    case ST_END:
      display("Robot " + GetRobotID() + " will not go deeper!");
      break;
    case ST_INIT:
      Init_This();
      State = ST_CENTER;
      break;
    case ST_CENTER:
      if ( GetX() < CenterX )      ok = Take_And_Move(1);
      else if ( GetX() > CenterX ) ok = Take_And_Move(3);
      else if ( GetZ() < CenterZ ) ok = Take_And_Move(0);
      else if ( GetZ() > CenterZ ) ok = Take_And_Move(2);
      else if ( Quarter < 1 && Count_Stock() == StartStock )
      {
        Quarter = -1;
        ok = Probe_And_Move(5);
      }
      else if ( Quarter < 3 )
      {
        Quarter += 1;
        Dir = (Dir + 1) % 4;
        CellCount = 0;
        RowCount = 0;
        State = ST_QUARTER;
        ok = Take_And_Move(Dir);
      }
      else
      {
        Depth += 1;
        HardLimitReached = ((StartY - GetY()) >= HARD_LIMIT);
        if ( Depth >= SOFT_LIMIT || HardLimitReached ) ok = false;
        else
        {
          Quarter = -1;
          ok = Take_And_Move(5);
        }
      }
      if ( ! ok )
      {
        display("Robot " + GetRobotID() + " going UP at (" + CenterX + "," + CenterZ + ")...");
        Init_Steps();
        State = ST_ASIDE;
      }
      break;
    case ST_QUARTER:
      if ( CellCount < (QUARTER_SIZE - 1) )
      {
        ok = Take_And_Move(Dir);
        CellCount += 1;
      }
      else if ( RowCount == (QUARTER_SIZE - 1) )
      {
        if ( (RowCount % 2) == 0 ) Turn_Left(); else Turn_Right();
        ok = Take_And_Move(Dir);
        if ( (RowCount % 2) == 0 ) Turn_Right(); else Turn_Left();
        State = ST_CENTER;
      }
      else
      {
        if ( (RowCount % 2) == 0 ) Turn_Right(); else Turn_Left();
        ok = Take_And_Move(Dir);
        if ( (RowCount % 2) == 0 ) Turn_Right(); else Turn_Left();
        CellCount = 0;
        RowCount += 1;
      }
      if ( ! ok )
      {
        display("Robot " + GetRobotID() + " going UP at (" + CenterX + "," + CenterZ + ")...");
        Init_Steps();
        State = ST_ASIDE;
      }
      break;
    case ST_ASIDE:
      switch ( CellCount )
      {
        case 0:
          CellCount = 1;
          ok = Take_And_Move(4);
          break;
        case 1:
          CellCount = 2;
          if ( StepXBeforeZ && GetX() < StepX )      ok = Take_And_Move(1);
          else if ( StepXBeforeZ && GetX() > StepX ) ok = Take_And_Move(3);
          else if ( GetZ() < StepZ )                 ok = Take_And_Move(0);
          else if ( GetZ() > StepZ )                 ok = Take_And_Move(2);
          else if ( GetX() < StepX )                 ok = Take_And_Move(1);
          else if ( GetX() > StepX )                 ok = Take_And_Move(3);
          break;
        case 2:
          CellCount = 0;
          ok = Take_And_Move(5);
          if ( GetX() == StepX && GetZ() == StepZ )  State = ST_CLIMB;
          break;
      }
      if ( ! ok )
      {
        State = ST_RETURN;
      }
      break;
    case ST_CLIMB:
      switch ( CellCount )
      {
        case 0:
        case 1:
          ok = Take_And_Move(4);
          if ( FlatSteps > 0 )
          {
            CellCount += 1;
            FlatSteps -= 1;
          }
          break;
        case 2:
          ok = Take_And_Move(Dir);
          break;
        case 3:
          ok = Take_And_Move(5);
          break;
      }
      CellCount += 1;
      if ( CellCount == 4 )
      {
        CellCount = 0;
        RowCount += 1;
        if ( GetY() >= StartY )
        {
          State = ST_RETURN;
        }
      }
      if ( RowCount == (QUARTER_SIZE * 2 + 2) )
      {
        Turn_Left();
        RowCount = 0;
      }
      if ( ! ok )
      {
        State = ST_RETURN;
      }
      break;
    case ST_RETURN:
      if ( GetY() == StartY )
      {
        if ( GetX() < StartX )       ok = Take_And_Move(1);
        else if ( GetX() > StartX )  ok = Take_And_Move(3);
        else if ( GetZ() < StartZ )  ok = Take_And_Move(0);
        else if ( GetZ() > StartZ )  ok = Take_And_Move(2);
        else
        {
          State = ST_DOCK;
          display("Robot " + GetRobotID() + " is docked.");
        }
      }
      else
      {
        if ( GetX() < CenterX )      ok = Take_And_Move(1);
        else if ( GetX() > CenterX ) ok = Take_And_Move(3);
        else if ( GetZ() < CenterZ ) ok = Take_And_Move(0);
        else if ( GetZ() > CenterZ ) ok = Take_And_Move(2);
        else if ( GetY() < StartY )  ok = Take_And_Move(4);
        else                         ok = Take_And_Move(5);
      }
      if ( ! ok )
      {
        display("Robot " + GetRobotID() + " is stuck at (" + GetX() + "," + GetY() + "," + GetZ() + ")!");
      }
      break;
    case ST_DOCK:
      slot = GetFirstUsedSlot();
      if ( slot < 0 )
      {
        if ( HardLimitReached ) State = ST_END;
        else
        {
          display("Robot " + GetRobotID() + " going down at (" + CenterX + "," + CenterZ + ")...");
          Reinit_This();
          State = ST_CENTER;
        }
      }
      else if ( GetSlot_Type(slot) in UnloadXYZ )
      {
        UnloadType = GetSlot_Type(slot);
        State = ST_TRANSPORT;
      }
      else if ( GetKey(KEY_LEARN) )
      {
        State = ST_LEARN;
      }
      else
      {
        display("Robot " + GetRobotID() + " needs to store " + GetVoxelName(GetSlot_Type(slot)));
      }
      break;
    case ST_LEARN:
      slot = GetFirstUsedSlot();
      if ( slot < 0 || GetKey(KEY_CANCEL) )
      {
        display("Robot " + GetRobotID() + " abandons.");
        State = ST_DOCK;
      }
      else if ( GetKey(KEY_VALIDATE) )
      {
        display("Robot " + GetRobotID() + " remembers.");
        UnloadXYZ[GetSlot_Type(slot)] <- [GetInfo(4), GetInfo(5), GetInfo(6)];
        State = ST_TRANSPORT;
      }
      else
      {
        display("Please stand where Robot " + GetRobotID() + " will store " + GetVoxelName(GetSlot_Type(slot)));
      }
      break;
    case ST_TRANSPORT:
      slot = GetFirstUsedSlot();
      if ( slot < 0 || GetSlot_Type(slot) != UnloadType ) State = ST_NEXTVOXEL;
      else
      {
        x = UnloadXYZ[UnloadType][0];
        y = UnloadXYZ[UnloadType][1];
        z = UnloadXYZ[UnloadType][2];
        if ( GetY() < y )                                 ok = Move(4);
        else if ( GetY() > y )                            ok = Move(5);
        else if ( GetX() < x )                            ok = Move(1);
        else if ( GetX() > x )                            ok = Move(3);
        else if ( GetZ() < z )                            ok = Move(0);
        else if ( GetZ() > z )                            ok = Move(2);
        else                                              State = ST_UNLOAD;
      }
      if ( ! ok ) display("Robot " + GetRobotID() + " needs help!");
      break;
    case ST_UNLOAD:
      slot = GetFirstUsedSlot();
      if ( slot < 0 || GetSlot_Type(slot) != UnloadType ) State = ST_NEXTVOXEL;
      else
      {
        for ( Dir = 0; Dir < 6; Dir += 1 )
        {
          if ( GetVoxelProp(Look(Dir), 1) )
          {
            ok = PushVoxelTo(Dir, GetSlot_Type(slot));
            if ( GetSlot_Quantity(slot) == 0 )            State = ST_NEXTVOXEL;
            break;
          }
        }
      }
      if ( ! ok ) display("Robot " + GetRobotID() + " cannot unload!");
      break;
    case ST_NEXTVOXEL:
      if ( GetZ() < StartZ )      ok = Move(0);
      else if ( GetZ() > StartZ ) ok = Move(2);
      else if ( GetX() < StartX ) ok = Move(1);
      else if ( GetX() > StartX ) ok = Move(3);
      else if ( GetY() < StartY ) ok = Move(4);
      else if ( GetY() > StartY ) ok = Move(5);
      else                        State = ST_DOCK;
      if ( ! ok ) display("Robot " + GetRobotID() + " needs help!");
      break;
  }
}

// This function is called when robot is loaded from save file or when created

function Voxel_Load()
{
  local name = Get_Save_Filename();
  print("read state file = " + name + "\r\n");
  try
  {
    local save = dofile(name);
    InitDir      = save.InitDir;
    State        = save.State;
    StartX       = save.StartX;
    StartY       = save.StartY;
    StartZ       = save.StartZ;
    CenterX      = save.CenterX;
    CenterZ      = save.CenterZ;
    StepX        = save.StepX;
    StepZ        = save.StepZ;
    StepXBeforeZ = save.StepXBeforeZ;
    FlatSteps    = save.FlatSteps;
    Dir          = save.Dir;
    Depth        = save.Depth;
    Quarter      = save.Quarter;
    CellCount    = save.CellCount;
    RowCount     = save.RowCount;
    StartStock   = save.StartStock;
    UnloadType   = save.UnloadType;
    UnloadXYZ    = save.UnloadXYZ;
  }
  catch (e)
  {
    print("Could not read state file for robot " + GetRobotID() + "\r\n  " + e + "\r\n");
  }
  if ( GetInfo(23) == 0 || GetInfo(23) == 4 )
  {
    print("Robot " + GetRobotID() + " set to initial state.\r\n");
    State = ST_INIT;
  }
  else
  {
    print("Robot " + GetRobotID() + " restored.\r\n");
  }
}

// This function is called when robot is unloaded to save file or when destroyed

function Voxel_Unload()
{
  local name = Get_Save_Filename();
  local save = file(name, "w");
  local slot, xyz, data;
  local code = "return {\n";
  code += "  InitDir      = " + InitDir + ",\n";
  code += "  State        = " + State + ",\n";
  code += "  StartX       = " + StartX + ",\n";
  code += "  StartY       = " + StartY + ",\n";
  code += "  StartZ       = " + StartZ + ",\n";
  code += "  CenterX      = " + CenterX + ",\n";
  code += "  CenterZ      = " + CenterZ + ",\n";
  code += "  StepX        = " + StepX + ",\n";
  code += "  StepZ        = " + StepZ + ",\n";
  code += "  StepXBeforeZ = " + (StepXBeforeZ ? "true" : "false") + ",\n";
  code += "  FlatSteps    = " + FlatSteps + ",\n";
  code += "  Dir          = " + Dir + ",\n";
  code += "  Depth        = " + Depth + ",\n";
  code += "  Quarter      = " + Quarter + ",\n";
  code += "  CellCount    = " + CellCount + ",\n";
  code += "  RowCount     = " + RowCount + ",\n";
  code += "  StartStock   = " + StartStock + ",\n";
  code += "  UnloadType   = " + UnloadType + ",\n";
  code += "  UnloadXYZ    = {\n";
  foreach ( slot, xyz in UnloadXYZ )
  {
    code += ("    [" + slot + "] = [" + xyz[0] + ", " + xyz[1] + ", " + xyz[2] + "],\n");
  }
  code += "  }\n}\n";
  data = blob(code.len());
  foreach ( slot in code )
  {
    data.writen(slot, 'b');
  }
  save.writeblob(data);
  save.close();
  print("Robot " + GetRobotID() + " saved.\r\n");
}

function Get_Save_Filename()
{
  local saves = GetPath(4);
  local sep = GetInfo(20);
  local nut = GetInfo(22);
  local robot = GetRobotID();
  return saves + sep + nut + "_" + robot + ".state";
}

function Init_This()
{
  local yaw = (GetInfo(7) + (PI/4)) % (PI*2);
  StartX = GetX();
  StartY = GetY();
  StartZ = GetZ();

  if (yaw < (PI/2))
  {
    InitDir = 0;
    CenterX = StartX;
    CenterZ = StartZ + QUARTER_SIZE + 1;
  }
  else if (yaw < PI)
  {
    InitDir = 1;
    CenterX = StartX + QUARTER_SIZE + 1;
    CenterZ = StartZ;
  }
  else if (yaw < (3*PI/2))
  {
    InitDir = 2;
    CenterX = StartX;
    CenterZ = StartZ - QUARTER_SIZE - 1;
  }
  else
  {
    InitDir = 3;
    CenterX = StartX - QUARTER_SIZE - 1;
    CenterZ = StartZ;
  }
  Reinit_This();
}

function Reinit_This()
{
  Depth = 0;
  Quarter = 3;
  StartStock = Count_Stock();
  Dir = InitDir;
}

function Count_Stock()
{
  local c = 0;
  for (local s = 0; s < GetInfo(24); s += 1)
  {
    c += GetSlot_Quantity(s);
  }
  return c;
}

function Take_And_Move(Dir)
{
  PickVoxel(Dir);
  if ( ! Move(Dir) )
  {
    display("Robot " + GetRobotID() + " could not move at (" + GetX() + "," + GetY() + "," + GetZ() + "), Dir. " + Dir + ", BlockType " + Look(Dir));
    return false;
  }
  return true;
}

function Probe_And_Move(Dir)
{
  if ( ! GetVoxelProp(Look(Dir), 0) ) PickVoxel(Dir);
  if ( ! Move(Dir) )
  {
    display("Robot " + GetRobotID() + " could not move at (" + GetX() + "," + GetY() + "," + GetZ() + "), Dir. " + Dir + ", BlockType " + Look(Dir));
    return false;
  }
  return true;
}

function Turn_Right()
{
  Dir = (Dir + 1) % 4;
}

function Turn_Left()
{
  Dir = (Dir + 3) % 4;
}

function Init_Steps()
{
  local base0Depth = StartY - GetY() - 1;
  local edgeSize = QUARTER_SIZE * 2;
  local sideSize = edgeSize + 2;
  local sidesCount = floor(base0Depth / sideSize);
  local afterSides = base0Depth - (sideSize * sidesCount);
  FlatSteps = 0;
  if ( afterSides >= edgeSize )
  {
    sidesCount += 1;
    FlatSteps = sideSize - afterSides;
    afterSides = 0;
  }
  RowCount = sideSize - 1 - afterSides;
  CellCount = 0;
  switch ( (InitDir + sidesCount) % 4 )
  {
    case 0:
      StepX = CenterX - QUARTER_SIZE - 1;
      StepZ = CenterZ - QUARTER_SIZE + afterSides;
      Dir = 2;
      break;
    case 1:
      StepX = CenterX - QUARTER_SIZE + afterSides;
      StepZ = CenterZ + QUARTER_SIZE + 1;
      Dir = 3;
      break;
    case 2:
      StepX = CenterX + QUARTER_SIZE + 1;
      StepZ = CenterZ + QUARTER_SIZE - afterSides;
      Dir = 0;
      break;
    case 3:
      StepX = CenterX + QUARTER_SIZE - afterSides;
      StepZ = CenterZ - QUARTER_SIZE - 1;
      Dir = 1;
      break;
  }
  StepXBeforeZ = (StepX > GetX() && StepZ > GetZ()) || (StepX < GetX() && StepZ < GetZ());
}

function display(message)
{
  if ( (GetGameTime() - Time) >= WAIT )
  {
    print(message + "\r\n");
    Display(message, WAIT, 2, 0);
    Time = GetGameTime();
  }
}

Just put the robot on the ground and stand behind it. Open its interface and load the program; it will start immediately to dig a 16×16 “square”, the centre of which is 8 voxels-or-so in front of the robot. The shape is not exactly a square because it is that of what 4 of the game’s robots around a compressor would do.

So:
—1— The robot digs 50 layers of ground.
—2— The robot climbs around the hole, all the while carving a stairway, just for you :-)
—3— When “docked” at its starting point, it will store each voxel at the right place.
—4— It then starts again with 50 new layers of ground, and stops just before reaching the green acid (provided you started at the top of the central blue zone).

When the robot does not know where to put a voxel, it says so. In that case:
—1— Press “L” (learn), and the robot will ask you to stand near a compressor, at the exact place where the robot will be able to transfer the voxels into the compressor (at the level of your feet, not your head!).
—2— When you stand at the right place, press “O” (ok), and the robot will remember.
—3— If instead you prefer to cancel, and go retrieve yourself the voxels from inside the robot, press “Q” (quit), and the robot will quit the learning-mode.

Oh, a few tips, available if you quit the game (or at least the world):
— Each save-file is plain-text, so you can fix mistakes, in case you wrongly taught the robot.
— You can even copy-paste the knowledge of a know-it-all robot, to a newer robot ;-)

Cheers

4
Gallery / Learning with Blackvoxel
« on: February 26, 2019, 08:29:55 am »
Hello,

You may have met me already on GitHub. I discovered Blackvoxel in late 2018, and enjoyed it very much.
In addition to being fun to play, with nice in-game programming capabilities, I found it also very educational where self-organization is concerned!

I wrote the following article, and I thought maybe you would be interested:
http://yalis.fr/cms/index.php/post/2019/02/20/Fun-with-Kanban%2C-episode-1
You might even want to plan missions along those lines ;-)

A second article is almost ready, still about Kanban.

And… well, since this place is about showcasing our creations, you can see my factory at the end of the article, producing almost everything.

And of course, I could not have gone so far, so fast, without the program I wrote for my programmable robots! This program:
  • digs a hole equivalent to what 4 regular robots around a storage would achieve;
  • when some depth has been reached, it climbs back up, all the while carving a staiway in case you need to go down;
  • when the top has been reached, it goes in turn to each location where each ore kind should be stored;
  • when an ore is still unknown, it asks where that ore should be stored;
  • when all has been stored, it goes back down the hole, and digs a new series of layers; and so on, until depth 1323 has been reached.

Pages: [1]