iriya_ufo’s blog

Curiosity was simply the first derivative of knowledge.

今さらだけど油売り算

キミならどう書く 2.0 - 2007 油売り算

以前に先輩から紹介されてたので,書こうと思ってコーディングしていたのだが,よく分からなくて無理だった.

んで,しばらく放置していたのだけれど,"学会発表の資料を作らなくてはいけない",という現実逃避がてら再度取り組んでみたらできてしまった.
おかげで学会発表用資料の中身はほとんど何も書いていないという….(パワポで作らなきゃいけないなんて苦痛だ)

  • ま,何はともあれソースを晒す
(define (main args)
  (if (= (length args) 4)
      (begin
	(let ((number-args (map string->number (cdr args))))
	  (apply solve number-args)))
      (error "Usage: gosh aburauri.scm a b c")))

(define solve
  (lambda ls
    (let ((a (car ls))
	  (b (cadr ls))
	  (c (caddr ls)))
      (print (list a b c))
      (print "--start--")
      (print (list a 0 0))
      (apply next-state (list a b c a 0 0)))))

;; next-state
;; 引数で次のようなリストを取る
;; (list aの容量 bの容量 cの容量 aの次の状態 bの次の状態 cの次の状態)
;; 再帰処理によって"次の状態"をもったリストに移行する
(define next-state
  (lambda ls
    (let ((a (car ls))
	  (b (cadr ls))
	  (c (caddr ls))
	  (next-a (list-ref ls 3))
	  (next-b (list-ref ls 4))
	  (next-c (list-ref ls 5)))
      (cond ((= (/ a 2) next-b)
	     (print "--end--"))
	    ((= b next-b)
	     (print (list (+ next-a next-b) 0 next-c))
	     (print (list (+ next-a next-b) next-c 0))
	     (apply next-state (list a b c (+ next-a next-b) next-c 0)))
	    ((and (= c next-c) (> (+ next-b next-c) b))
	     (print (list next-a b (- c (- b next-b))))
	     (apply next-state (list a b c next-a b (- c (- b next-b)))))
	    ((= c next-c)
	     (print (list next-a (+ next-b next-c) 0))
	     (apply next-state (list a b c next-a (+ next-b next-c) 0)))
	    (else
	     (print (list (- next-a c) next-b c))
	     (apply next-state (list a b c (- next-a c) next-b c)))))))
  • 実行結果
iriya@iriya-laptop> gosh aburauri.scm 10 7 3          [~/.../scheme/src-sample]
(10 7 3)
--start--
(10 0 0)
(7 0 3)
(7 3 0)
(4 3 3)
(4 6 0)
(1 6 3)
(1 7 2)
(8 0 2)
(8 2 0)
(5 2 3)
(5 5 0)
--end--
  • 違う引数とかでやってみる
iriya@iriya-laptop> gosh aburauri.scm 16 9 5          [~/.../scheme/src-sample]
(16 9 5)
--start--
(16 0 0)
(11 0 5)
(11 5 0)
(6 5 5)
(6 9 1)
(15 0 1)
(15 1 0)
(10 1 5)
(10 6 0)
(5 6 5)
(5 9 2)
(14 0 2)
(14 2 0)
(9 2 5)
(9 7 0)
(4 7 5)
(4 9 3)
(13 0 3)
(13 3 0)
(8 3 5)
(8 8 0)
--end--
  • やってること

アルゴリズムというべきほどのものでもありません.
くそまじめに条件書いただけです.
条件によって変更されたリストを,新しいリストとしてnext-stateに渡すという再帰的処理で解いてます.

  • このプログラムがだめだめなところ

モジュール化が全然できていない.(結果表示も条件分岐も全部next-stateの中でやっている)
故に汎用性ゼロ
同じ状態が来たら無限ループに逝く.
解ける条件を記述していない.

さて,一応書けたわけですがどうみてもへぼいです.
自分としては"これはだめだろう…"と思うのですが,どこをどう直せばいいコードになるのかよく分かりません.
コードを他の人に添削してもらえたりするのってすっげー幸せなことなんだなぁと思いました.
(ということなので,恥ずかしいコードだったけど晒している)

ほんの少し修正

bの容量=cの容量の倍数,となっている場合は無限ループ逝きなので,その場合はエラーになるように変更.
他にもエラー処理をほんのちょっと追加.
aが奇数
a/2 > b
c > b
c = 0
あと分からへん.

  • 修正変更点(solve関数)のみ記載
(define solve
  (lambda ls
    (let ((a (car ls))
	  (b (cadr ls))
	  (c (caddr ls)))
      (print (list a b c))
      (if (or (and (not (eqv? c 1)) (= 1 (/ c (gcd b c))))
	      (odd? a)
	      (> (/ a 2) b)
	      (> c b)
	      (= c 0))
	  (error "その引数では解けないですぅ >_<"))
      (print "--start--")
      (print (list a 0 0))
      (apply next-state (list a b c a 0 0)))))