読者です 読者をやめる 読者になる 読者になる

あのねノート

せんせいあのね、パソコンで字が書けるようになったよ

たぬき暗号メーカーを作ってみる

Racket 遊び

わけのわからない文章の横にたぬきの絵が描いてあって、文章から「た」という文字を抜けば読めるようになるあれです。

Racketではreadという関数で標準入力を使えます。文字入力はシンボルとして扱われます。(""で囲うと文字列扱いになるみたいです)

> (read)
abc
'abc

こんな感じ。
入力したシンボルをsymbol->stringで文字列に置き換え、string->listで文字のリストにすれば入力をリストとして扱うことができそう。もっといい方法もありそうですが…
というわけで入力を文字のリストにする関数input->clistを作ります。

(define (input->clist)
  (let*
      ((input (read))
       (instring (symbol->string input))
       (clist (string->list instring)))
      clist)
  )

let使う必要ないかもですがこんな感じで文字のリストが返ってきます。

> (input->clist)
abc
'(#\a #\b #\c)

リストの要素の間に適当に「た」を挟めたらうれしいので、最初の文字と付け足したい文字と付け足す個数を受け取ってくっつけたリストを返す関数を作ります。

(define (append-c first c n)
  (define (c-list n) ;文字cをn個並べたリストを作る
    (if (= n 0)
        '()
        (append (list c) (c-list (- n 1))))
    )
  (append (list first) (c-list n)) ;文字firstとc-listをくっつけたリストを返す
  )

appendはリスト同士をつなぐので文字をリストに入れないといけないということを忘れててちょっとつまずいたりしてました。
動作確認するとこんな感じ。

> (append-c #\a #\c 2)
'(#\a #\c #\c)
> (append-c #\a #\c 0)
'(#\a)

あとはこれを再帰的に呼んで、挟む個数を乱数で出せばよさそうです。

(define (tanuki-maker)
  (define (tanuki-fact l) ;リストlを受け取って、1文字ごとに「た」を0~2文字挟む
    (if (null? (cdr l))
        (append-c (car l) #\た (random 3)) 
        (append (append-c (car l) #\た (random 3)) (tanuki-fact (cdr l)))))
  (let
      ((input (input->clist))) ;入力をリストに置き換える
    (list->string (tanuki-fact input)) ;「た」を挟んでできたリストを文字列にして返す
      )
  )

こうなります。

> (tanuki-maker)
ほんじつはせいてんなり
"ほたんじたつたはたたせたたいたてたんたなたたり"

元に戻す関数も作ります。

(define (inputanuki s) ;入力から文字sを取り除いて返す
  (define (remtanuki l)
    (if (null? (cdr l))
        (if (char=? s (car l))
            '()
            (list (car l)))
        (if (char=? s (car l))
            (remtanuki (cdr l))
            (append (list (car l)) (remtanuki (cdr l)))))
    )
  (let
      ((input (input->clist)))
    (list->string (remtanuki input))
    )
  )

こうなります。

> (inputanuki #\a)
abcaabc
"bcbc"

先ほどの"ほたんじたつたはたたせたたいたてたんたなたたり"を入力してみます。

> (inputanuki #\た)
ほたんじたつたはたたせたたいたてたんたなたたり
"ほんじつはせいてんなり"

無事元に戻すことができました。
何を再帰させないといけないかいつもわからなくなって混乱してしまうのがよくないなと思いました。あと、入力の例外(元の入力に「た」が入ってるとまずい)とかを工夫したほうがいい気もします。