著者:飯尾淳
本連載の第5 回(Vol.51、2017 年12 月号)で、バーティカルバー(垂直棒)が3 本立っているという理由から「ハノイの塔」というパズルを取り上げました。今回は、そのときの考察を思い出しつつ、ハノイの塔を解くプログラムを再び考えます。
ただし、今回は三つの塔を「上から見下ろした」状態、俯瞰(ふかん)で考えます。至ってシンプルなルールで解ける面白さを、動作の可視化プログラムを用いて確認してみましょう。
シェルスクリプトマガジン Vol.60は以下のリンク先でご購入できます。![]()
![]()
const COLORS = [ 'crimson', 'forestgreen', 'yellow',
'royalblue', 'saddlebrown', 'hotpink', 'darkorange',
'darkmagenta' ];
const N_DISKS = COLORS.length;
const BASE_LENGTH = 200;
const C_WIDTH = 3.732 * BASE_LENGTH;
const C_HEIGHT = 3.500 * BASE_LENGTH;
const DISK_R = 0.9 * BASE_LENGTH;
const POLE_R = 15;
const POSITIONS = { 'Source' : [0.268, 0.714],
'Auxiliary' : [0.500, 0.286],
'Destination' : [0.732, 0.714] };
class Position {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class Disk {
constructor(level) {
this.level = level;
this.color = COLORS[level];
this.r = (DISK_R-POLE_R)*(N_DISKS-level)
/ N_DISKS + POLE_R;
}
}
class Tower {
constructor(name, disks, direction=null) {
this.name = name;
this.disks = [];
for (var i = 0; i < disks; i++)
{ this.disks.push(new Disk(i)); }
this.direction = direction;
var rx, ry;
[rx,ry] = POSITIONS[name];
this.pos = new Position(rx*C_WIDTH, ry*C_HEIGHT);
}
}
var src = new Tower('Source', N_DISKS);
var aux = new Tower('Auxiliary', 0, src);
var dst = new Tower('Destination', 0, src);
// 円盤の数(N_DISKS)が奇数のときはDestinationを、
// そうでないときはAuxiliaryを向くようにする
src.direction = (N_DISKS % 2 == 1) ? dst : aux;
function setup() {
createCanvas(C_WIDTH, C_HEIGHT);
frameRate(30);
}
function draw() {
// put drawing code here
}
class Disk {
constructor(level) {
(略)
}
draw(pos) {
stroke('black');
fill(this.color);
ellipse(pos.x, pos.y, 2*this.r);
}
}
class Tower {
constructor(name, disks, direction=null) {
(略)
}
draw() {
var pos = this.pos;
var pos2 = this.direction.pos;
var sx, sy, dx, dy, r;
// 円盤を描く
this.disks.forEach(function(d) { d.draw(pos) })
// 支柱を描く
stroke('brown');
fill('white');
ellipse(pos.x, pos.y, 2*POLE_R);
// 向きを描く
stroke('navy');
[sx, sy] = [pos.x, pos.y ];
[dx, dy] = [pos2.x, pos2.y];
r = POLE_R / Math.sqrt((dx-sx)*(dx-sx)+(dy-sy)*(dy-sy));
[dx, dy] = [(dx-sx)*r+sx, (dy-sy)*r+sy];
line(sx, sy, dx, dy);
}
}
(略)
function setup() {
createCanvas(C_WIDTH, C_HEIGHT);
frameRate(30);
}
function draw() {
background('beige');
[src, aux, dst].forEach(function(t) { t.draw(); })
}