Personal tools
You are here: Home ブログ 井上 もし堀北真希がEmacsユーザだったら
« December 2010 »
Su Mo Tu We Th Fr Sa
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
Recent entries
Apache2.4のリリース予定は来年(2011年)初め(あくまで予定) inoue 2010-12-23
Herokuの発音 inoue 2010-12-20
雑誌記事「ソフトウェア・テストPRESS Vol.9」の原稿公開 inoue 2010-12-18
IPA未踏のニュース inoue 2010-12-15
労基法とチキンゲーム inoue 2010-12-06
フロントエンドエンジニア inoue 2010-12-03
ASCII.technologies誌にMapReduceの記事を書きました inoue 2010-11-25
技術評論社パーフェクトシリーズ絶賛発売中 inoue 2010-11-24
雑誌連載「Emacsのトラノマキ」の原稿(part8)公開 inoue 2010-11-22
RESTの当惑 inoue 2010-11-22
「プログラマのためのUXチートシート」を作りました inoue 2010-11-19
「ビューティフルコード」を読みました inoue 2010-11-16
Categories
カテゴリなし
 
Document Actions

もし堀北真希がEmacsユーザだったら

こんな問題が出ました。

  • 3つのコップがあります。容積はそれぞれ16,9,7
  • 容積16のコップには水が一杯で、容積9と7のコップは空です
  • コップ間で水を移動して、容積16と9にそれぞれ8ずつになるようにしなさい
  • コップ間の水の移動は、移動先が一杯になるか、移動元が空になる単位でのみ可能です

言葉では冗長なので、少し形式化します。

容積Nのコップに水量nがある状態を、(n/N)と表現すると、

(16/16) (0/9) (0/7)
が初期状態で、
(8/16) (8/9) (0/7)
がゴールです。

遷移の具体例
(16/16) (0/9) (0/7)
から一回で遷移できる状態は、
(7/16) (9/9) (0/7)  と  (9/16) (0/9) (7/7)
のふたつです。

自分で解くのは簡単すぎるので、Emacsにやらせます。

(defun get-transitions (bins)
  (list (trans bins 0 1) (trans bins 0 2) (trans bins 1 0) (trans bins 1 2) (trans bins 2 0) (trans bins 2 1)))

(defun trans (bins src-pos dest-pos)
  (let ((src (nth src-pos bins)) (dest (nth dest-pos bins)))
    (if (and (> (cdr src) 0) (> (car dest) (cdr dest)))
        (let* ((bins-dup (copy-alist bins)) 
               (move (min (cdr src) (- (car dest) (cdr dest))))
               (src-on-dup (nth src-pos bins-dup)) (dest-on-dup (nth dest-pos bins-dup)))
          (setcdr src-on-dup (- (cdr src-on-dup) move))
          (setcdr dest-on-dup (+ (cdr dest-on-dup) move))
          bins-dup)
      bins)))

(defun my-search (bins goal history route output-buf)
  (if (equal bins goal)
      (print-route (reverse (cons bins route)) output-buf)
    (if (not (member bins history))
        (progn 
          (setq history (cons bins history))
          (setq route (cons bins route))
          (let ((trans-lst (get-transitions bins)))
            (while trans-lst
              (my-search (car trans-lst) goal history route output-buf)
              (setq trans-lst (cdr trans-lst))))
          (setq route (cdr route))))))

(defun print-bins (bins buf &optional indent msg)
  (with-current-buffer buf
    (goto-char (point-max))
    (if (and (boundp 'msg) msg)
        (insert msg))
    (if (and (boundp 'indent) indent)
        (insert (make-string indent ?\040)))
    (insert (number-to-string (cdr (nth 0 bins))) " " (number-to-string (cdr (nth 1 bins))) " " (number-to-string (cdr (nth 2 bins))) "\n")))
 
(defun print-route (route buf)
  (with-current-buffer buf
    (goto-char (point-max))
    (insert "Route ")
    (insert (number-to-string (length route)))
    (insert "\n")
    (while route
      (print-bins (car route) buf)
      (setq route (cdr route)))))

出力系の処理が半分近くありますが(後者ふたつの関数)、本質では無いので無視してください。

問題は次のようにして解けます(出力用バッファ#outを指定)。

(let ((output-buf (get-buffer-create "#out")))
  (my-search '((16 . 16) (9 . 0) (7 . 0)) '((16 . 8) (9 . 8) (7 . 0)) nil nil output-buf)
  (switch-to-buffer-other-window output-buf))

最小パスは次のようになりました(16はパスの長さ。遷移回数は15回)。

Route 16
16 0 0
7 9 0
7 2 7
14 2 0
14 0 2
5 9 2
5 4 7
12 4 0
12 0 4
3 9 4
3 6 7
10 6 0
10 0 6
1 9 6
1 8 7
8 8 0

my-searchがメイン関数で、get-transitionsが下請け関数、transが更にその下請け関数です。

使い方を見てデータ構造の予想はついていると思いますが、(16/16) (0/9) (0/7)を((16 . 16) (0 . 9) (0 . 7))で表しています(=連想リストを要素にもつリスト)。

trans関数の実装がうまくありません。破壊的操作(setcdr)もしていますし、冗長なわりに読みやすくもありません。そもそも、本当にやりたいことはget-transitions関数で、現在の状態から一回で遷移可能な状態のリストを返すことです。0 1や0 2などのハードコードを無くせそうな気がします(副次的にtransも無くなる)。それは堀北真希さんへの宿題にします。

ぼくの目標は、問題を解くより速く、問題を解くEmacs lispのコードを書けるようになることです。

The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/inoue/lisp-backtrack/tbping

Re:もし堀北真希がEmacsユーザだったら

Posted by jian at 2007-03-30 18:08
XSLT でやると:

_<_?xml version="1.0" encoding="windows-1251"?>
_<_xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

_<_xsl:template match="/">
_<_table border="1">
_<_td>_16__<_/td>
_<_td>_9__<_/td>
_<_td>_7__<_/td>
_<_xsl:call-template name="u"/>
_<_/table>
_<_/xsl:template>

_<_xsl:template name="u">
_<_xsl:param name="o16" select="16"/>
_<_xsl:param name="o9" select="0"/>
_<_xsl:param name="o7" select="0"/>

_<_tr>
_<_td>_<_xsl:value-of select="$o16"/>_<_/td>
_<_td>_<_xsl:value-of select="$o9"/>_<_/td>
_<_td>_<_xsl:value-of select="$o7"/>_<_/td>
_<_/tr>

_<_xsl:if test="$o16 + $o7 != $o9">
_<_xsl:call-template name="u">
_<_xsl:with-param name="o16" select="$o16 - 9 + $o7"/>
_<_!-- _<_xsl:with-param name="o9" select="(16 - ($o16 - 9 + $o7)) - 7"/>-->
_<_xsl:with-param name="o9" select="18 - $o16 - $o7"/>
_<_xsl:with-param name="o7" select="7"/>
_<_/xsl:call-template>
_<_/xsl:if>

_<_/xsl:template>

_<_/xsl:stylesheet>



xml はなんでもよいと。
結果は:
16 0 0
7 2 7
5 4 7
3 6 7
1 8 7
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.