date: 2013-10-19
author: ka
8 クイーン問題なら聞いたことある?
その一般化された問題
チェス盤に 8 つのクイーンを互いに効かないように配置する
将棋と似ている
将棋もチェスも源流はインドのチャトランガというゲーム
王将を「詰め」れば勝ちなのと同様,チェスではキングを「チェックメイト」すれば勝ち
盤面が 8 * 8
取った駒 (チェス用語ではピース) が使えない
引き分けがよくある
前に 1 マスだけ進める
+-+-+-+-+-+ | | | | | | +-+-+-+-+-+ | | |*| | | +-+-+-+-+-+ | | |P| | | +-+-+-+-+-+
最初の一回だけ 2 マス進める
+-+-+-+-+-+ | | |*| | | +-+-+-+-+-+ | | |*| | | +-+-+-+-+-+ | | |P| | | +-+-+-+-+-+
斜めにある駒しか取れない
前にある駒はとれない
+-+-+-+-+-+ | | | | | | +-+-+-+-+-+ | |*| |*| | +-+-+-+-+-+ | | |P| | | +-+-+-+-+-+
ポーン同士が衝突してお互い動けなくなることがよくある
桂馬と似た動き
桂馬と違い左右と後ろに同様の動きが出来る
+-+-+-+-+-+ | |*| |*| | +-+-+-+-+-+ |*| | | |*| +-+-+-+-+-+ | | |N| | | +-+-+-+-+-+ |*| | | |*| +-+-+-+-+-+ | |*| |*| | +-+-+-+-+-+
角行と同じ
+-+-+-+-+-+ |*| | | |*| +-+-+-+-+-+ | |*| |*| | +-+-+-+-+-+ | | |B| | | +-+-+-+-+-+ | |*| |*| | +-+-+-+-+-+ |*| | | |*| +-+-+-+-+-+
飛車と同じ
+-+-+-+-+-+ | | |*| | | +-+-+-+-+-+ | | |*| | | +-+-+-+-+-+ |*|*|R|*|*| +-+-+-+-+-+ | | |*| | | +-+-+-+-+-+ | | |*| | | +-+-+-+-+-+
飛車 + 角行 (ルーク + ビショップ)
+-+-+-+-+-+ |*| |*| |*| +-+-+-+-+-+ | |*|*|*| | +-+-+-+-+-+ |*|*|Q|*|*| +-+-+-+-+-+ | |*|*|*| | +-+-+-+-+-+ |*| |*| |*| +-+-+-+-+-+
実際最強である
王将と同じ
+-+-+-+-+-+ | | | | | | +-+-+-+-+-+ | |*|*|*| | +-+-+-+-+-+ | |*|Q|*| | +-+-+-+-+-+ | |*|*|*| | +-+-+-+-+-+ | | | | | | +-+-+-+-+-+
+-+-+-+-+-+-+-+-+ |R|N|B|Q|K|B|N|R| (Black) +-+-+-+-+-+-+-+-+ |P|P|P|P|P|P|P|P| +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ |P|P|P|P|P|P|P|P| +-+-+-+-+-+-+-+-+ |R|N|B|Q|K|B|N|R| (White) +-+-+-+-+-+-+-+-+
それぞれ Wikipedia へのリンクです
チェスでは「王手」のことを「チェック」と言う
チェックをかけつつ相手が次にどう動いても相手のキングを取れる状況になること
これが勝ちの条件
+-+-+-+-+-+-+-+-+ | | | | | |Q| |K| (<- Black King) +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | |K| +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+ | | | | | |N| |K| (<- Black King) +-+-+-+-+-+-+-+-+ | | | | | |K| | | +-+-+-+-+-+-+-+-+ | | | | | |B| | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+
チェスでは「チェックがかかっていない状態」で相手を詰み状態にしてしまうと引き分けになる
+-+-+-+-+-+-+-+-+ | | | | | | | |K| (<- Black King) +-+-+-+-+-+-+-+-+ | | | | | |Q| | | +-+-+-+-+-+-+-+-+ | | | | | | | |K| +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+ | | | | | | |K| | (<- Black King) +-+-+-+-+-+-+-+-+ | | | | | | |P| | +-+-+-+-+-+-+-+-+ | | | | | | |K| | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+
先ほど紹介された最強の駒ことクイーン
これを盤面上に 8 つ配置する
ただしどの 2 つの駒もお互いに取られないようにする
実物のチェスにはクイーンは白と黒の 1 つずつしかない
仕方がないのでポーンをクイーンの代わりにしてみる
+-+-+-+-+-+-+-+-+ |Q| | | | | | | | +-+-+-+-+-+-+-+-+ | | | | | | |Q| | +-+-+-+-+-+-+-+-+ | | | | |Q| | | | +-+-+-+-+-+-+-+-+ | | | | | | | |Q| +-+-+-+-+-+-+-+-+ | |Q| | | | | | | +-+-+-+-+-+-+-+-+ | | | |Q| | | | | +-+-+-+-+-+-+-+-+ | | | | | |Q| | | +-+-+-+-+-+-+-+-+ | | |Q| | | | | | +-+-+-+-+-+-+-+-+
Prolog という論理プログラミング言語
問題のルールと制約を記述するだけ
アルゴリズムを考える必要なし
詳しくは 7 つの言語 7 つの世界にて (本棚にあります)
N-queens problem - Rosetta Code
英語の解説は存在する
以降このコードを読み解くことにする
(def size 8) (defn extends? [v n] (let [k (count v)] (not-any? true? (for [i (range k) :let [vi (v i)]] (or (= vi n) ;check for shared row (= (- k i) (Math/abs (- n vi)))))))) ;check for shared diagonal (defn extend [vs] (for [v vs n (range 1 (inc size)) :when (extends? v n)] (conj v n))) (def solutions (nth (iterate extend [[]]) size)) (doseq [s solutions] (println s)) (println (count solutions) "solutions")
solutions 定義
(def solutions (nth (iterate extend [[]]) size))
extend 関数とは何か?
extend 関数
(defn extend [vs] (for [v vs n (range 1 (inc size)) :when (extends? v n)] (conj v n)))
vs: 初期値は [[]]
(range 1 (inc size))
今 size が 8 なのでこの部分は '(1 2 3 4 5 6 7 8) になる
extend 関数は以下のように読める
(defn extend [vs] (for [v vs n '(1 2 3 4 5 6 7 8) :when (extends? v n)] (conj v n)))
extend? 関数
(defn extends? [v n] (let [k (count v)] (not-any? true? (for [i (range k) :let [vi (v i)]] (or (= vi n) ;check for shared row (= (- k i) (Math/abs (- n vi)))))))) ;check for shared diagonal