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)
下の空白は、タップしたボタンのログを表示させたいので、そのためのスペースです。
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)))))
キーボードのイメージはとりあえずこれで行こうと思いますが、もしかしたら途中で変えるかもしれません。
続きます。
*1:機能の確認がしやすいように家にある電卓(カシオのSL-720L)と同じにしました。