忍者ブログ

cc-memo

Computer Craft のメモ

nekoPosi() / nekoNega()

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

コメント

ただいまコメントを受けつけておりません。

nekoPosi() / nekoNega()



lib_neko_0.1.1
マイニングタートルで、ブランチマイニングをする時などに使用する、
必要なブロックだけを根こそぎ採集するプログラム(ライブラリ)。

現物指定の「nekoPosi()」と
除外対象を指定する「nekoNega()」の2種類の関数を用意した。
※どちらも、呼び出し前のスロットの選択状態を復元することができないので注意。

それぞれ短所有り。どちらかというとnekoNega()のほうが良い?
nekoPosi() : 石炭、レッドストーン、ラピスラズリ、ダイヤの鉱石サンプルを「シルクタッチ」エンチャントのついたツルハシを使って用意する必要があり、面倒くさい。
また、MODの追加鉱物等がある場合、現物指定は現実的ではないかも。

nekoNega() : 除外対象の想定に漏れがあると、どこまでも採集に出かけてしまい、帰ってこなくなる。(要塞を掘り当ててしまい、延々と「石レンガ」を採集してしまうとか。)
★破壊できないブロックを掘ろうとして動きが止まる不具合有り。後日このページのソースを修正予定。
直した。

lib_turtle_0.2.3
・「lib_neko」で使用する関数(myForward()とか)について、localの指定を外した。
myExcavate()を引数無しで呼べるように、myDigUp()、myDig()、myDigDown()を作った。
・myDig()、myForward()等が、内部で呼び出しているturtle.dig()、turtle.forward()の戻り値を返すように修正。
・移動処理実行時にOut of fuelとなった場合に、スクリプトを中断して、燃料を継ぎ足すか、あきらめるかを選択できるようにした。

testNekoPosi
「lib_neko」の関数「nekoPosi()」をテストする為のプログラム。
スロット1と2に「現物」を置いておく必要有り。
マイニングタートルの正面に、収集対象であるブロックを置いた状態で実行する必要有り。

testNekoNega
「lib_neko」の関数「nekoNega()」をテストする為のプログラム。
スロット1~4に「除外対象」を置いておく必要有り。
マイニングタートルの正面に、収集対象であるブロックを置いた状態で実行する必要有り。

以下ソース。

testNekoPosi

dofile("lib_neko_0.1.1");
local ary = { 1, 2 };
nekoPosi(1, ary);

testNekoNega
dofile("lib_neko_0.1.1");
local ary = { 1, 2, 3, 4 };
nekoNega(1, ary);

lib_neko_0.1.1
dofile("lib_turtle_0.2.3");

local function digBack()
  local rslt;
  turtle.turnLeft();
  turtle.turnLeft();
  rslt = myDig();
  turtle.turnRight();
  turtle.turnRight();
  return rslt;
end

local function dir(name_, fromDir_, compareFunc_, detectFunc_,
                   forwardFunc_, digFunc_, backFunc_, backDigFunc_)
  return
    {
      name        = name_,
      fromDir     = fromDir_,
      compareFunc = compareFunc_,
      detectFunc  = detectFunc_,
      forwardFunc = forwardFunc_,
      digFunc     = digFunc_,
      backFunc    = backFunc_,
      backDigFunc = backDigFunc_,
    };
end

local dirInfo = { };
dirInfo[0] = dir("top",    2, turtle.compareUp,   turtle.detectUp,   myUp,      myDigUp,   myDown, myDigDown);
dirInfo[1] = dir("front",  4, turtle.compare,     turtle.detect,     myForward, myDig,     myBack, digBack);
dirInfo[2] = dir("bottom", 0, turtle.compareDown, turtle.detectDown, myDown,    myDigDown, myUp,   myDigUp);
dirInfo[3] = dir("left",   4, turtle.compare,     turtle.detect,     myForward, myDig,     myBack, digBack);
dirInfo[4] = dir("back",   4, turtle.compare,     turtle.detect,     myForward, myDig,     myBack, digBack);
dirInfo[5] = dir("right",  4, turtle.compare,     turtle.detect,     myForward, myDig,     myBack, digBack);

local stack = { };

local function doCompare(posiFlg, compareFunc, detectFunc, slotAry)
  for i, slot in ipairs(slotAry) do
    turtle.select(slot);
    if compareFunc() then
      return posiFlg;
    end
  end
  if posiFlg then
    return false;
  else
    return detectFunc();
  end
end

local function doNekosogi(posiFlg, dirCode, slotAry)

  local dcDI = dirInfo[dirCode];
  if not doCompare(posiFlg, dcDI.compareFunc, dcDI.detectFunc, slotAry) then
    return;
  end
  if false == dcDI.digFunc() then
    return;
  end
  dcDI.forwardFunc();

  table.insert(stack, { toDir = dirCode, progress = 0 });
  local current = stack[table.maxn(stack)];
    
  while true do
    if 6 <= current.progress then
      turtle.turnLeft();
      if not dirInfo[current.toDir].backDigFunc() then
        error("Since the return path was shut by unbreakable block, turtle cannot move.");
      end
      dirInfo[current.toDir].backFunc();
      table.remove(stack);

      current = stack[table.maxn(stack)];
      if nil == current then
        break;
      end
    else
      if 3 <= current.progress then
        turtle.turnLeft();
      end
      local curStaIdx = table.maxn(stack);
      if current.progress ~= dirInfo[current.toDir].fromDir then
        local cpDI = dirInfo[current.progress];
        if doCompare(posiFlg, cpDI.compareFunc, cpDI.detectFunc, slotAry) then
          if cpDI.digFunc() then
            cpDI.forwardFunc();
            table.insert(stack, { toDir = current.progress, progress = 0 });
            current = stack[table.maxn(stack)];
          end
        end
      end
      stack[curStaIdx].progress = stack[curStaIdx].progress + 1;
    end
  end
end

-- dirCode : 0(top), 1(front), 2(bottom)
function nekoPosi(dirCode, slotAry)
  doNekosogi(true, dirCode, slotAry);
end

-- dirCode : 0(top), 1(front), 2(bottom)
function nekoNega(dirCode, slotAry)
  doNekosogi(false, dirCode, slotAry);
end

lib_turtle_0.2.3
dofile("lib_log");

userEventHandler = nil;

local function myPlace(para1)
  if para1 == 0 then
    return turtle.placeUp();
  elseif para1 == 1 then
    return turtle.place();
  elseif para1 == 2 then
    return turtle.placeDown();
  end
end

local function myThrow(para1, para2)
  if para1 == 0 then
    return turtle.dropUp(para2);
  elseif para1 == 1 then
    return turtle.drop(para2);
  elseif para1 == 2 then
    return turtle.dropDown(para2);
  end
end

local function myExcavate(para1)
  if para1 == 0 then
    if turtle.detectUp() then
      for i = 1, 40 do
        turtle.digUp();
        sleep(0.5);
        if not turtle.detectUp() then
          return true;
        end
      end
      return false;
    else
      return true;
    end
  elseif para1 == 1 then
    if turtle.detect() then
      for i = 0, 9 do
        turtle.dig();
        sleep(0);
        if false == turtle.detect() then
          return true;
        end
      end
      for i = 0, 9 do
        turtle.dig();
        sleep(0.5);
        if false == turtle.detect() then
          return true;
        end
      end
      return false;
    else
      return true;
	end
  elseif para1 == 2 then
    if turtle.detectDown() then
      return turtle.digDown();
    else
      return true;
    end
  end
end

function myDigUp()
  return myExcavate(0);
end

function myDig()
  return myExcavate(1);
end

function myDigDown()
  return myExcavate(2);
end

local function myZzz(para1)
  sleep(para1 / 1000);
end

local function myOutput(para1, para2)
  local dir = { [0] = "top",  [1] = "front", [2] = "bottom",
                [3] = "left", [4] = "back",  [5] = "right" };
  if para2 == 1 then
    rs.setOutput(dir[para1], true);
  else
    rs.setOutput(dir[para1], false);
  end
end

local function mySuck(para1)
  if para1 == 0 then
    return turtle.suckUp();
  elseif para1 == 1 then
    return turtle.suck();
  elseif para1 == 2 then
    return turtle.suckDown();
  end
end

local function myAttack(para1)
  if para1 == 0 then
    return turtle.attackUp();
  elseif para1 == 1 then
    return turtle.attack();
  elseif para1 == 2 then
    return turtle.attackDown();
  end
end

function refuelPrompt(moveFunc)
  local firstTime = true;
  while true do
    local rslt, msg;
    if nil ~= moveFunc then
      rslt, msg = moveFunc();
    else
      if firstTime then
        firstTime = false;
        rslt = false;
        msg  = "Out of fuel";
      else
        return true;
      end
    end
    if not rslt and msg == "Out of fuel" then
      print("Out of fuel. please select [r]efuel or [q]uit.");
      print("(r/q)");
      local ch = read();
      if "q" == ch then
        print("Are you sure you want to stop the script?");
        print("(y/n)");
        ch = read();
        if "q" == ch then
          error("out of fuel.");
        end
      elseif "r" == ch then
        local selSlot = 1;
        while true do
          print("Please type current selected slot number.");
          ch = read();
          local num = tonumber(ch);
          if nil ~= num and 1 <= num and num <= 16 then
            selSlot = num;
            break;
          else
            print("Wrong input. Please retry.");
          end
        end
        while true do
          print("please set fuel item and type slot number.");
          print("When you finish refueling, Please type q.");
          print("FuelLevel = " .. turtle.getFuelLevel());
          ch = read();
          local num = tonumber(ch);
          if nil ~= num and 1 <= num and num <= 16 then
            turtle.select(num);
            local fRslt, fMsg = turtle.refuel();
            if not fRslt then
              print(fMsg);
            end
          elseif "q" == ch then
            turtle.select(selSlot);
            break;
          else
            print("Wrong input. Please retry.");
          end
        end
      end
    else
      return rslt, msg;
    end
  end
end

local function myMove(dirName, moveFunc, detectFunc, attackFunc)
  local rslt, msg;
  while true do
    --rslt, msg = moveFunc();
    rslt, msg = refuelPrompt(moveFunc);
    if rslt then
      return true;
    else
      if moveFunc == turtle.back then
        turtle.turnRight();
        turtle.turnRight();
      end
      if detectFunc() then
        if moveFunc == turtle.back then
          turtle.turnLeft();
          turtle.turnLeft();
        end
        return false;
      else
        for i = 0, 9 do
          attackFunc();
          attackFunc();
          attackFunc();
          if moveFunc == turtle.back then
            if true == turtle.forward() then
              turtle.turnLeft();
              turtle.turnLeft();
              return true;
            end
          else
            --if true == moveFunc() then
            if true == refuelPrompt(moveFunc) then
              return true;
            end
          end
        end
        if moveFunc == turtle.back then
          turtle.turnLeft();
          turtle.turnLeft();
        end
        while true do
          print("move [" .. dirName .. "] failed. retry? (y/n)");
          local input = read();
          if "y" == input then
            break;
          elseif "n" == input then
            error("program stopped by user request.");
          else
            print("wrong input. type y or n.");
          end
        end
      end
    end
  end
end

function myForward()
  return myMove("forward", turtle.forward, turtle.detect, turtle.attack);
end

function myBack()
  return myMove("back", turtle.back, turtle.detect, turtle.attack);
end

function myUp()
  return myMove("up", turtle.up, turtle.detectUp, turtle.attackUp);
end

function myDown()
  return myMove("down", turtle.down, turtle.detectDown, turtle.attackDown);
end

local function myUserEvent(para1)
  if nil ~= userEventHandler then
    userEventHandler(para1);
  end
end

local cmdInfo =
{
  f = { paraCnt = 0, func = myForward;        }, -- [f]orward
  b = { paraCnt = 0, func = myBack;           }, -- [b]ack
  l = { paraCnt = 0, func = turtle.turnLeft;  }, -- turn [l]eft
  r = { paraCnt = 0, func = turtle.turnRight; }, -- turn [r]ight
  u = { paraCnt = 0, func = myUp;             }, -- [u]p
  d = { paraCnt = 0, func = myDown;           }, -- [d]own
  s = { paraCnt = 1, func = turtle.select;    }, -- [s]elect
  p = { paraCnt = 1, func = myPlace;          }, -- [p]lace
  t = { paraCnt = 2, func = myThrow;          }, -- [t]hrow = drop
  e = { paraCnt = 1, func = myExcavate;       }, -- [e]xcavate = dig
  z = { paraCnt = 1, func = myZzz;            }, -- [z]zz = sleep
  o = { paraCnt = 2, func = myOutput;         }, -- set [o]utput (redstone) 
  k = { paraCnt = 1, func = mySuck;           }, -- suc[k]
  a = { paraCnt = 1, func = myAttack;         }, -- [a]ttack
  v = { paraCnt = 1, func = myUserEvent;      }, -- user e[v]ent
};

local function getParam(command, idx)
  local buff = "";
  local ch = "";

  for i = idx, command:len() do
    ch = command:sub(i, i);
    if ch == "," then
      if buff == "" then
        return nil, i + 1;
      else
        return tonumber(buff), i + 1;
      end
    elseif nil ~= string.find("0123456789", ch, 1, true) then
      buff = buff .. ch;
    else
      if buff ~= "" then
        return tonumber(buff), i;
      end
    end
  end
  if buff == "" then
    return nil, command:len() + 1;
  else
    return tonumber(buff), command:len() + 1;
  end
end

local function get1Cmd(command, idx)
  local cmd = string.sub(command, idx, idx);
  local para1, para2, nextIdx, paraCnt;

  if nil ~= cmdInfo[cmd] then
    paraCnt = cmdInfo[cmd].paraCnt;
  else
    error("unknown command [" .. cmd .. "]");
  end

  if -1 == paraCnt then
    return nil, nil, nil, idx + 1;
  elseif paraCnt == 0 then
    return cmd, nil, nil, idx + 1;
  elseif paraCnt == 1 then
    para1, nextIdx = getParam(command, idx + 1);
    return cmd, para1, nil, nextIdx;
  elseif paraCnt == 2 then
    para1, nextIdx = getParam(command, idx + 1);
    para2, nextIdx = getParam(command, nextIdx);
    return cmd, para1, para2, nextIdx;
  end
end

local function checkLoop(command)
  local kBgn = {""};
  local loopInfo = {};

  local ch, repeatCnt, nextIdx, kBgnIdx;
  for i = 1, command:len() do
    ch = command:sub(i, i);
    if "(" == ch then
      table.insert(kBgn, i);
    elseif ")" == ch then
      repeatCnt, nextIdx = getParam(command, i + 1);
      loopInfo[i] = { beginIdx   = table.remove(kBgn),
                      endIdx     = i,
                      nextIdx    = nextIdx,
                      repeatCnt  = repeatCnt,
                      currentCnt = 0 };
      i = nextIdx;
    end
  end
  return loopInfo;
end

function doCommand(command)
  
  command = command .. " ";
  local loopInfo = checkLoop(command);

  local cmd, para1, para2, nextIdx, ch;

  local i = 1;
  while true do
    ch = command:sub(i, i);
    if ")" == ch then
      loopInfo[i].currentCnt = loopInfo[i].currentCnt + 1;
      if loopInfo[i].repeatCnt <= loopInfo[i].currentCnt then
        loopInfo[i].currentCnt = 0;
        i = loopInfo[i].nextIdx;
      else
        i = loopInfo[i].beginIdx;
      end
    elseif " " == ch then
      i = i + 1;
    elseif "\n" == ch then
      i = i + 1;
    elseif "(" == ch then
      i = i + 1;
    else
      cmd, para1, para2, nextIdx = get1Cmd(command, i);
      i = nextIdx;

      if cmd ~= nil then
        cmdInfo[cmd].func(para1, para2);
      end
    end
    if command:len() <= i then
      break;
    end
  end
end

PR

コメント

プロフィール

HN:
kssr
性別:
非公開

Twitter

最古記事

(04/25)
(04/26)
(04/27)
(04/28)
(04/29)

アンテナ・ランキング