Simple Scheme で電卓をつくってみる

Simple Schemeで電卓を作ります。関数電卓とかスマホに最初から入ってるようなのとかじゃなくて、普通のやつ(「普通電卓」というのですね。それを作ります )。

最初にキーボードのイメージを作りましょう。

まずはボタンのリストです*1

(define button-labels
  '("%"  "7" "8" "9" "÷" "MR"
    "√"  "4" "5" "6" "×" "M-"
    "C"  "1" "2" "3" "-" "M+"
    "AC" "0" "." "=" "+"))

実際のボタン配置(予定)と似た見た目になるように改行してあります。

画面上の配置位置を決めるために、画面の幅を取得しましょう。

(define width (image-width (empty-scene)))

横に6つ並べるので、画面左端のx座標を-1、右端のx座標を6としたときにx座標が0,1,2,3,4,5となるような位置にボタンを置くのがよさそうです。

この座標を画面上の実際の座標に変換する関数を定義しましょう。y座標は、ボタン同士の上下の距離が左右と同じになるように設定し、ウインドウの場所を空けるために少し下げます。

(define (conv-x x) (/ (* width (+ 1 x)) 7))
(define (conv-y y) (/ (* width (+ 2 y)) 7))

place-imageで左上のボタンから順に配置していきます。

(define (place-buttons x y button-labels scn)
  (if (null? button-labels)
      scn
      (let ((scn (place-image (text (car button-labels) 80 "black")
                              (conv-x x) (conv-y y) scn)))
        (if (>= x 5)
            (place-buttons 0 (++ y) (cdr button-labels) scn)
            (place-buttons (++ x) y (cdr button-labels) scn)))))

(define keyboard (place-buttons 0 0 button-labels (empty-scene)))

表示してみましょう。

(show-image keyboard)

f:id:brv00:20191027101208j:plain:w250

下の空白は、タップしたボタンのログを表示させたいので、そのためのスペースです。

ACやMRが少し大きく見えるので調整して、ついでに色分けしましょう。 place-buttonsの定義を以下の定義群と置き替えます。

(define-struct button-category (labels size color))
(define button-categories
  (list
   (make-button-category '("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" ".") 80 "gray")
   (make-button-category '("+" "-" "×" "÷" "=" "%" "√")                 70 "black")
   (make-button-category '("MR" "M+" "M-")                              60 "blue")
   (make-button-category '("AC" "C")                                    60 "red")))

(define (place-buttons x y button-labels scn)
  (if (null? button-labels)
      scn
      (let* ((b (car button-labels))
             (bc (letrec ((find (lambda (lis)
                                  (if (ormap (lambda (l) (string=? b l))
                                             (button-category-labels (car lis)))
                                      (car lis)
                                      (find (cdr lis))))))
                   (find button-categories)))
             (scn (place-image (text b (button-category-size bc)
                                     (button-category-color bc))
                               (conv-x x) (conv-y y) scn)))
        (if (>= x 5)
            (place-buttons 0 (++ y) (cdr button-labels) scn)
            (place-buttons (++ x) y (cdr button-labels) scn)))))

f:id:brv00:20191027111144j:plain:w250

キーボードのイメージはとりあえずこれで行こうと思いますが、もしかしたら途中で変えるかもしれません。

続きます。

(ここまでのソースコード)

*1:機能の確認がしやすいように家にある電卓(カシオのSL-720L)と同じにしました。