ALGOBIT

2010/09/20

ハノイとバベルの塔 第二階 – 端末出力 C および Haskell

Filed under: 離散的な気まぐれ — タグ: , , — Kohyama @ 23:35

移動手順を文字列で出力するプログラムを考えます.

左の杭を A, 真ん中の杭を B, 右の杭を C とします. 小さい順に 1番から n番まで円盤には番号が付いているとします.
A の杭にある全ての円盤を C の杭に移します.

円盤の個数をコマンドライン引数として与えると

move disc #1 from A to C
move disc #2 from A to B
...

のように, 移動するべき円盤の番号と, 移動元および移動先の杭の名称を出力するようにします. 引数が無い場合は円盤の数を 3 とすることにします.

円盤の数を 3 としたときの実行結果は以下のようになります.

move disc #1 from A to C
move disc #2 from A to B
move disc #1 from C to B
move disc #3 from A to C
move disc #1 from B to A
move disc #2 from B to C
move disc #1 from A to C

以下のように考えて実装してみます.
n番以下の全ての円盤を杭srcから杭dstに動かすには, もうひとつの杭を tmp として,

  • n – 1 番以下の全ての円盤を杭src から, 杭tmp に動かす.
  • n番の円盤を杭src から杭dst に動かす.
  • n – 1 番以下の全ての円盤を杭tmp から, 杭dst に動かす.

n – 1番以下の全ての円盤を杭src’ から, 杭dst’ に動かすには, src’ を新しい src として, dst’ を新しい dst として, n – 1 を新しい n として, 上記と同じことをします.
ただし, 新しく n として設定した値が 0であれば, 目的達成です.

C 言語で記述したものです.

#include <stdio.h>
#include <stdlib.h>

static void
hanoi(char src, char tmp, char dst, int n)
{
	if (n == 0)
		return;
	hanoi(src, dst, tmp, n - 1);
	printf("move disc #%d from %c to %c\n", n, src, dst);
	hanoi(tmp, src, dst, n - 1);
}

int
main(int argc, char *argv[])
{
	int n = (argc < 2)?3:atoi(argv[1]);
	hanoi('A', 'B', 'C', n);
	return 0;
}

以下は Haskell で記述したものです.

import System

format :: (Int, Char, Char) -> String
format (n,s,d) = "move disc #" ++ (show n) ++ " from " ++ [s] ++ " to " ++ [d]

hanoi :: Char -> Char -> Char -> Int -> [(Int, Char, Char)]
hanoi _ _ _ 0 = []
hanoi s t d n = hanoi s d t (n - 1) ++
                [(n, s, d)] ++
                hanoi t s d (n - 1)

main = do args <- getArgs
          let n | (not . null) args = read (head args)::Int
                | otherwise = 3
          putStr $ unlines $ map format $ hanoi 'A' 'B' 'C' n

6〜10行目が, 主要な関数の定義です. C の場合と違い, この関数の中で出力を行うわけではありません.
15行目が, 動作の本体であり, $ を挟んで, 右側から左側に処理されたデータが引き渡されていきます.
hanoi ‘A’ ‘B’ ‘C’ n は [(1, 'A', 'C'), (2, 'A', 'B'), ...] のような, 円盤を動かす手を表すタプルのリストを返します.
map format で ["move disc #1 from A to C", "move disc #2 from A to B", ...] のように, 各タプルを整形,
unlines が “move disc #1 from A to C\nmove disc #2 from A to B\n…” (\n は改行です) のように行の集合に変換,
putStr が出力します.
UNIX のパイプに似ていると思う方もいらっしゃるかもしれません.

このような小さなプログラムでは, 大きな違いとはなりませんが, 出力の方法が, パズルを解く部分に組み込まれていないところが, 分離性が良いですね.


Graham Hutton
オーム社
発売日:2009-11-11

Bryan O’Sullivan,John Goerzen,Don Stewart
オライリージャパン
発売日:2009-10-26


2010/09/19

ハノイとバベルの塔 第一階 – イントロダクション

Filed under: 離散的な気まぐれ — タグ: — Kohyama @ 04:10

「ハノイの塔」は, プログラミング言語の学習過程で題材に使われることの多いパズルです.

以下のルールに従ってすべての円盤を右端の杭に移動させられれば完成。
3本の杭と、中央に穴の開いた大きさの異なる複数の円盤から構成される。
最初はすべての円盤が左端の杭に小さいものが上になるように順に積み重ねられている。
円盤を一回に一枚ずつどれかの杭に移動させることができるが、小さな円盤の上に大きな円盤を乗せることはできない。
n枚の円盤すべてを移動させるには 2n – 1 回の手数がかかる。
解法に再帰的アルゴリズムが使用可能な問題として有名であり、プログラミングにおける再帰的呼出しの例題としてもよく用いられる。

出典: Wikipedia

新しいプログラミング言語を学ぼうとするとき, 利用経験のあるライブラリと同じ目的を持った別のライブラリを利用するとき. ほぼ同等の機能をそれぞれに実装してみるということは, 言語やライブラリの比較にもなりますし, 題材自体について既知であれば, 入力方法や出力方法を変える場合の練習にもなります.
この「ほぼ同等の機能」として「パズル『ハノイの塔』を解く過程の表示」は 「文字列 “Hello, World!” を表示する」よりも, もう少し複雑な格好の題材ではないかと思います.

「バベルの塔」は, 地球上に様々な言語があることの理由として創世記で語られる伝説の塔です.

全地は同じ発音、同じ言葉であった。
時に人々は東に移り、シナルの地に平野を得て、そこに住んだ。
彼らは互に言った、「さあ、れんがを造って、よく焼こう」。こうして彼らは石の代りに、れんがを得、しっくいの代りに、アスファルトを得た。
彼らはまた言った、「さあ、町と塔とを建てて、その頂を天に届かせよう。そしてわれわれは名を上げて、全地のおもてに散るのを免れよう」。
時に主は下って、人の子たちの建てる町と塔とを見て、
言われた、「民は一つで、みな同じ言葉である。彼らはすでにこの事をしはじめた。彼らがしようとする事は、もはや何事もとどめ得ないであろう。
さあ、われわれは下って行って、そこで彼らの言葉を乱し、互に言葉が通じないようにしよう」。
こうして主が彼らをそこから全地のおもてに散らされたので、彼らは町を建てるのをやめた。
これによってその町の名はバベルと呼ばれた。主がそこで全地の言葉を乱されたからである。主はそこから彼らを全地のおもてに散らされた。

出典: 旧約聖書 創世記(口語訳) by Wikisource

本稿では, 「ハノイの塔」を解くロジックを複数のプログラミング言語で, その過程を複数の描画方法で実装し, プログラミング言語の特性や, ライブラリの適用可能性を探ります.
日記的ではなく順次加筆修正によりバージョンアップ, および続編執筆していこうと思います.


オライリージャパン
発売日:2010-09-27

言語設計者達へのインタビューをまとめた本です. インタビュアーが考えていることとも言えます.
ここから何かが得られるか分かりませんが, 読みものとしてとても楽しめました.

2010/09/15

サイト構造を考え中

Filed under: 離散的な気まぐれ — Kohyama @ 14:16

日記的なコンテンツと, そうでないコンテンツの両方を WordPress で管理しようと思い
WordPress を専用ディレクトリに配置する などを参考に更新中.
.htaccess は無くても, 「ブログのアドレス」の変更を保存してから, パーマリンクの設定を保存すれば, サイトトップに .htaccess が作成される模様.
で, この後どうするか.

Copyright © 2010 Yoshinori Kohyama All Rights Reserved.