javascriptで書いてみる

クリティカルシンキング・入門篇、実践篇 - AFTER★SE7EN
二年前に書いた上記の書き込みの下記問題

例えば印象に残ったテーマは、

3匹のネコと3匹のネズミをボートで川を渡すような問題だ。

・手漕ぎボートには一度に2匹しかのることができない。

・向こう岸についたボートがこちらにもどってくるためには、誰かがボートをこがなければならない。

・川のどちら側でも、ネコの数がネズミを上回ってはいけない。そうしないとネコはネズミを食べる。

6匹全員が手漕ぎボートで川を渡るにはどうしたらいいだろうか?

これを解いてみようとして、Rhinoを入れてjavascriptを書いてみた。

function moveFowardOneNezumi(a,b){
   var index = a.indexOf("ネズミ");
   if(index != -1){
      a.splice(index,1);
      b.push("ネズミ");
   }
}

function moveFowardOneNeko(a,b){
   var index = a.indexOf("ネコ");
   if(index != -1){
      a.splice(index,1);
      b.push("ネコ");
   }
}

function moveFowardTwoNezumi(a,b){
   moveFowardOneNezumi(a,b);
   moveFowardOneNezumi(a,b);
   
}

function moveFowardNezumiAndNeko(a,b){
   moveFowardOneNezumi(a,b);
   moveFowardOneNeko(a,b);
}

function moveFowardTwoNeko(a,b){
   moveFowardOneNeko(a,b);
   moveFowardOneNeko(a,b);
}

function moveBackOneNezumi(a,b){
   var index = b.indexOf("ネズミ");
   if(index != -1){
      b.splice(index,1);
      a.push("ネズミ");
   }
}

function moveBackOneNeko(a,b){
   var index = b.indexOf("ネコ");
   if(index != -1){
      b.splice(index,1);
      a.push("ネコ");
   }
}

function moveBackTwoNezumi(a,b){
   moveBackOneNezumi(a,b);
   moveBackOneNezumi(a,b);
}

function moveBackNezumiAndNeko(a,b){
   moveBackOneNezumi(a,b);
   moveBackOneNeko(a,b);
}

function moveBackTwoNeko(a,b){
   moveBackOneNeko(a,b);
   moveBackOneNeko(a,b);
}

function countNeko(list){
   var tmp = new Array();
   var tmp = [].concat(list);
   var countNeko = 0;
   while(tmp.indexOf("ネコ") > -1){
      var index = tmp.indexOf("ネコ");
      tmp.splice(index,1);
      countNeko = countNeko+1;
   }
   return countNeko;
}

function countNezumi(list){
   var tmp = new Array();
   tmp = [].concat(list);
   var countNezumi = 0;
   while(tmp.indexOf("ネズミ") > -1){
      var index = tmp.indexOf("ネズミ");
      tmp.splice(index,1);
      countNezumi = countNezumi+1;
   }
   return countNezumi;
}

function checkNekoNezumiCount(tmp){
   var cntNeko = countNeko(tmp);
   var cntNezumi = countNezumi(tmp);

   if(cntNeko > cntNezumi){
   	  if((cntNeko == 3) || (cntNezumi == 0)){
   	     return true;
      } else {
         return false;
      }
   } else {
      return true;
   }
}

function checkFinish(a, b){
   var countNeko = 0;
   var countNezumi = 0;
   if(b.length == 0){
   	   return false;
   } else {
      while(b.indexOf("ネコ") > -1){
         var index = b.indexOf("ネコ");
         b.splice(index,1);
         countNeko = countNeko+1;
      }
      while(b.indexOf("ネズミ") > -1){
         var index = b.indexOf("ネズミ");
         b.splice(index,1);
         countNezumi = countNezumi+1;
      }
   }
   if((countNeko == 3)&&(countNezumi == 3)){
      return true;
   } else {
      return false;
   }
}
      
function recursive(a, b, direction, count){
   for(i=0; i<5; i+1){
   	   print(i);
   	   print(direction);
   	  countNekoA = countNeko(a);
   	  countNekoB = countNeko(b);
   	  countNezumiA = countNezumi(a);
   	  countNezumiB = countNezumi(b);
   	  print(countNekoA);
   	  print(countNekoB);
   	  print(countNezumiA);
   	  print(countNezumiB);
   	  print(a);
   	  print(b);
   	  print(count);
   	  
      if((i==0) && (direction == "forward") && (countNezumiA >= 1)){
         moveFowardOneNezumi(a,b);
      }
      else if((i==1) && (direction == "forward") && (countNezumiA >= 2)){
         moveFowardTwoNezumi(a,b);
      }
      else if((i==2) && (direction == "forward") && (countNekoA >= 1) && (countNezumiA >= 1)){
         moveFowardNezumiAndNeko(a,b);
      }
      else if((i==3) && (direction == "forward") && (countNekoA >= 1)){
         moveFowardOneNeko(a,b);
      }
      else if((i==4) && (direction == "forward") && (countNekoA >= 2)){
         moveFowardTwoNeko(a,b);
      }
      else if((i==0) && (direction == "back") && (countNekoB >= 2)){
      	 moveBackTwoNeko(a,b);
      }
      else if((i==1) && (direction == "back") && (countNekoB >= 1)){
      	 moveBackOneNeko(a,b);
      }
      else if((i==2) && (direction == "back") && (countNekoB >= 1) && (countNezumiB >= 1)){
         moveBackNezumiAndNeko(a,b);
      }
      else if((i==3) && (direction == "back") && (countNezumiB >= 2)){
         moveBackTwoNezumi(a,b);
      }
      else if((i==4) && (direction == "back") && (countNezumiB >= 1)){
         moveBackOneNezumi(a,b);
      }
      else {
      	  print("error");
      }
      if(checkNekoNezumiCount(a) && checkNekoNezumiCount(b)){
         if(direction == "forward"){
            direction = "back";
         } else {
            direction = "forward";
         }
         if(checkFinish(a,b) == false){
         	count = count + 1;
            arguments.callee(direction, count);
         } else {
            print(count+"<br>");
            return;
         }
      }
   }
}

recursive(new Array("ネコ","ネコ","ネコ","ネズミ","ネズミ","ネズミ"), new Array(), "forward", 0);

ごらんの通りに未完成なのだが、
javascriptを書いてみて、これは引数に配列を渡すと強制的に参照渡しになってしまうので
中々厄介な気がした。
ちょっとさすがにコード量も大げさなので、Rubyで続きの作業をするかもしれない。
基本的にはこんな感じの再帰になっているはず。

再帰関数(両岸の状態,舟の移動先)
{
 for ( k=0; k<5; k++ ){
  k番目の移動方法で移動
  if (ネコが両岸でネズミより少ない) {
   舟の移動の向きを変える;
   両岸の状態を更新
   if (向こう岸に全員移動しきってない) {
    再帰関数 (両岸の状態,舟の移動の向き);
   else
    結果を表示
   }
  }
 }
}

以下は作業用メモ:

class Side
   attr_accessor :cats, :rats

   def initialize(cats, rats)
      @cats = cats
      @rats = rats
   end
   def catOut
      @cats.pop()
   end
   def catIn
      @cats.push("c")
   end
   def ratOut
      @rats.pop()
   end
   def ratIn
      @rats.push("r")
   end
end

class Boat
   def moveOneCat(boat, sideA, sideB, direction)
      if(direction == "forward") then
         sideA.catOut
         sideB.catIn
      else
         sideB.catOut
         sideA.catIn
      end
   end
   def moveOneRat(boat, sideA, sideB, direction)
      if(direction == "forward") then
         sideA.ratOut
         sideB.ratIn
      else
         sideB.ratOut
         sideA.ratIn
      end
   end
   def moveTwoCat(boat, sideA, sideB, direction)
      boat.moveOneCat(boat, sideA, sideB, direction)
      boat.moveOneCat(boat, sideA, sideB, direction)
   end
   def moveCatRat(boat, sideA, sideB, direction)
      boat.moveOneCat(boat, sideA, sideB, direction)
      boat.moveOneRat(boat, sideA, sideB, direction)
   end
   def moveTwoRat(boat, sideA, sideB, direction)
      boat.moveOneRat(boat, sideA, sideB, direction)
      boat.moveOneRat(boat, sideA, sideB, direction)
   end
end

class Checker
   def countCats(side)
      return side.cats.length
   end
   def countRats(side)
      return side.cats.length
   end
   def checkCatsRatsCount(side)
      check = Checker.new()
      if(check.countCats(side) > check.countRats(side)) then
         return false
      else
         return true
      end
   end
   def checkFinish(side)
      check = Checker.new()
      if((check.countCats(side) == 3) and (check.countRats(side) == 3)) then
         return true
      else
         return false
      end
   end
end

def recursive(sideA, sideB, boat, movelog, direction, count)
   for i in [1, 2, 3, 4, 5]
      
      p sideA
      p sideB
      print(direction)
      print(count)
      print(movelog)



      check = Checker.new()
      if((i == 4) and (check.countCats(sideA) >= 1) and (direction == "forward") and (movelog != "moveOneCatBack"))
         boat.moveOneCat(boat, sideA, sideB, direction)
         movelog = "moveOneCatForward"
      elsif((i == 4) and (check.countCats(sideB) >= 1) and (direction == "back") and (movelog != "moveOneCatForward"))
         boat.moveOneCat(boat, sideA, sideB, direction)
         movelog = "moveOneCatBack"
      elsif((i == 3) and (check.countCats(sideA) >= 2) and (direction == "forward") and (movelog != "moveTwoCatBack"))
         boat.moveTwoCat(boat, sideA, sideB, direction)
         movelog = "moveTwoCatForward"
      elsif((i == 3) and (check.countCats(sideB) >= 2) and (direction == "back") and (movelog != "moveTwoCatForward"))
         boat.moveTwoCat(boat, sideA, sideB, direction)
         movelog = "moveTwoCatBack"
      elsif((i == 1) and (check.countCats(sideA) >= 1) and (check.countRats(sideA) >= 1) and (direction == "forward") and (movelog != "moveCatRatBack"))
         boat.moveCatRat(boat, sideA, sideB, direction)
         movelog = "moveCatRatForward"
      elsif((i == 1) and (check.countCats(sideB) >= 1) and (check.countRats(sideB) >= 1) and (direction == "back") and (movelog != "moveCatRatForward"))
         boat.moveCatRat(boat, sideA, sideB, direction)
         movelog = "moveCatRatBack"
      elsif((i == 2) and (check.countRats(sideA) >= 1) and (direction == "forward") and (movelog != "moveOneRatBack"))
         boat.moveOneRat(boat, sideA, sideB, direction)
         movelog = "moveOneRatForward"
      elsif((i == 2) and (check.countRats(sideB) >= 1) and (direction == "back") and (movelog != "moveOneRatForward"))
         boat.moveOneRat(boat, sideA, sideB, direction)
         movelog = "moveOneRatBack"
      elsif((i == 5) and (check.countRats(sideA) >= 2) and (direction == "forward") and (movelog != "moveTwoRatBack"))
         boat.moveTwoRat(boat, sideA, sideB, direction)
         movelog = "moveTwoRatForward"
      elsif((i == 5) and (check.countRats(sideB) >= 2) and (direction == "back") and (movelog != "moveTwoRatForward"))
         boat.moveTwoRat(boat, sideA, sideB, direction)
         movelog = "moveTwoRatBack"
      else
         print("error")
      end
      
      if((check.checkCatsRatsCount(sideA)) and (check.checkCatsRatsCount(sideB))) then
         if(direction == "forward") then
            direction = "back"
         else
            direction = "forward"
         end
         if(check.checkFinish(sideB) == false) then
            count = count++
            recursive(sideA, sideB, boat, movelog, direction, count)
         else
            print(count)
         end
      end
   end
end

sideA = Side.new(%w(c c c), %w(r r r))
sideB = Side.new(%w(),%w())
boat = Boat.new()
direction = "forward"
count = 0
movelog = "";

recursive(sideA, sideB, boat, movelog, direction, count)