Last Update: Sep.30,2013

JavaScript Sample

動作確認:○IE8(WinXP) ○Firefox24

■ 問題(忙しい月旅行)

地球に4台のロケットがある。これをパイロット2人で月まで運びたい。ただし、黒いロケットは月まで片道1日かかり、同様に、赤は2日、青は4日、白は8日かかる。また、ロケットには2人まで乗ることができる。さて、2週間以内にすべてのロケットを月まで運べるだろうか。

■ プログラムについて

双方向探索でビットパターンを使っていますが、重いですね。

■ 解答

(0) 黒赤青白[→][←] [0,0,0,0]
(1) 黒青白[赤→][←] [0,1,0,0]
(2) 青白[→][←]黒赤 [0,0,0,0]
(3) 黒青白[→][←]赤 [0,0,0,0]
(4) 黒[青白→][←]赤 [0,0,3,7]
(5) 黒[青白→][←]赤 [0,0,2,6]
(6) 黒[青白→][←]赤 [0,0,1,5]
(7) 黒[白→][←]赤青 [0,0,0,4]
(8) 黒[白→][←赤]青 [0,1,0,3]
(9) 黒赤[白→][←]青 [0,0,0,2]
(10) 赤[白→][←]黒青 [0,0,0,1]
(11) 赤[→][←]黒青白 [0,0,0,0]
(12) 黒赤[→][←]青白 [0,0,0,0]
(13) [赤→][←]黒青白 [0,1,0,0]
(14) [→][←]黒赤青白 [0,0,0,0]

■ ソース

window.onload = function() {
/*
 *  Fly Me to the Moon
 *
 */
var K = 1, R = 2, B = 4, W = 8, M = 16, F = 32;

var mem = [ K, R, B, W ], pil = [ M, F ];

var spd = [ 1, 2, 4, 8 ];

/* 全員 */
var all = K|R|B|W|M|F;

/* 最初と最後の状態 */
var start = { bank:all, roc:0, prev:null, back:false };
var end = { bank:all<<6, roc:0, prev:null, back:true };

/* ロケットの飛行パターン */
var pt = [
  K|M,     R|M,     B|M,     W|M,
  K|F,     R|F,     B|F,     W|F,
  K|M|F,   R|M|F,   B|M|F,   W|M|F,
  K|M|R|F, K|M|B|F, K|M|W|F, R|M|B|F,
  R|M|W|F, B|M|W|F, 0
];

/* 値の取得と設定 */
var getv = function(p, n) {
  return (p.bank>>6*n)&0x3f;
};

var putv = function(p, n, val) {
  p.bank &= ~(0x3f<<6*n);
  p.bank |= val<<6*n;
};

var getroc = function(p, n) {
  return (p.roc>>4*n)&0xf;
};

var putroc = function(p, n, val) {
  p.roc &= ~(0xf<<4*n);
  p.roc |= val<<4*n;
};

/* 結果の表示 */
var output = function(n) {
  var s = '';
  if (n&K) s += '黒';
  if (n&R) s += '赤';
  if (n&B) s += '青';
  if (n&W) s += '白';
  if (n&M) s += '<span>飛</span>';
  if (n&F) s += '<span>飛</span>';
  return s;
};

var printroc = function(p) {
  var r = [];
  for (var i in mem) {
    r.push(getroc(p, i));
  }
  return r.toString();
};

var print = function(a, b) {
  var r = [], p = a;
  while (p) {
    r.unshift(p);
    p = p.prev;
  }
  p = b.prev;
  while (p) {
    r.push(p);
    p = p.prev;
  }
  if (r.length > 15) return false;
  s += '<div>';
  for (var i in r) {
    s += '(' + i + ') ';
    s += output(getv(r[i], 0));
    s += '[' + output(getv(r[i], 2)) + '→]';
    s += '[←' + output(getv(r[i], 3)) + ']';
    s += output(getv(r[i], 1));
    s += ' [' + printroc(r[i]) + ']';
    s += '<br />';
  }
  s += '</div>';
  return true;
};

/* 履歴のパターンと照合 */
var regist = function() {
  for (var i = 0; i < arguments.length; i++) {
    var t = arguments[i];
    hash[t.bank+','+t.roc] = t;
  }
};

var search = function(t) {
  return !!hash[t.bank+','+t.roc];
};

var goal = function(t) {
  var p = hash[t.bank+','+t.roc];
  if (p && p.back != t.back) return p;
  return null;
};

/* ロケットの操作関数 */
var count = function(n) {
  var c = [ 0, 0 ];
  for (var i in mem) {
    if (n&mem[i]) c[0]++;
  }
  for (var i in pil) {
    if (n&pil[i]) c[1]++;
  }
  return c;
};

var indexOf = function(arr, val) {
  for (var i in arr) {
    if (arr[i] == val) return i;
  }
  return -1;
};

var _step = function(t, n) {
  var id = indexOf(mem, n);
  for (var i = 2; i <= 3; i++) {
    var v1 = getv(t, i);
    var v2 = getv(t, t.back ? i-2 : 3-i);
    if (!(v1&n^n)) {
      var d = t.back ? getroc(t, id)+1 : getroc(t, id)-1;
      putroc(t, id, d);
      if (getroc(t, id) != (t.back ? spd[id] : 0)) continue;
      putroc(t, id, 0);
      var c = count(v1);
      if (c[0] == 1 && c[1] == 2) {
        putv(t, i, v1^(n|M|F));
        putv(t, t.back ? i-2 : 3-i, v2|n|M|F);
      } else if (v1&M) {
        putv(t, i, v1^(n|M));
        putv(t, t.back ? i-2 : 3-i, v2|n|M);
      } else {
        putv(t, i, v1^(n|F));
        putv(t, t.back ? i-2 : 3-i, v2|n|F);
      }
    }
  }
};

var step = function(t) {
  for (var i in mem) {
    _step(t, mem[i]);
  }
};

var select = function(no, now, next, pt) {
  var v1 = getv(now, no);
  var v2 = getv(now, next.back ? 3-no : no+2);
  if (!(v1&pt^pt)) {
    putv(next, no, v1^pt);
    putv(next, next.back ? 3-no : no+2, v2|pt);
    for (var i in mem) {
      if (pt&mem[i]) {
        var d = next.back ? 0 : spd[i];
        putroc(next, i, d);
      }
    }
    return true;
  }
  return false;
};

/* キューとハッシュ表を用意 */
var queue = [ start, end ], hash = {};

/* ロケット発射(双方向探索) */
var trip = function() {
  var found, res;
  regist(start, end);
  while (queue.length > 0) {
    var now = queue.shift();
    for (var i in pt) {
      for (var j in pt) {
        var next = {};
        next.bank = now.bank;
        next.roc = now.roc;
        next.prev = now;
        next.back = now.back;
        if (select(0, now, next, pt[i]) &&
            select(1, now, next, pt[j])) {
          step(next);
          if (found = goal(next)) {
            res = found.back ? print(next, found)
                             : print(found, next);
            if (res) return;
          } else if (!search(next)) {
            regist(next);
            queue.push(next);
          }
        }
      }
    }
  }
};

/* 実行と解答表示 */
var s = '';
trip();
document.getElementById('answer').innerHTML = s;

/* ソース表示用 */
var jsparser_obj = new JSParser();
var ro = document.getElementById('ro_script');
var src = ro.text || ro.innerHTML;
document.getElementById('viewsrc').innerHTML = jsparser_obj.parse(src);
};