「精霊の箱」の貧者の像と富者の像のようなものを書きました
『精霊の箱 上: チューリングマシンをめぐる冒険』の1章で登場する貧者の像と富者の像のような動作をする関数rich_and_poorを書きました。のようなと言っているのは、最後の状態の処理で@posが逆に移動するのですが、そこは無視しているからです。そのまま2章の文字列の比較も書こうとしましたが、ループのところ、えーっと正規表現で言うところのe*をオートマトンで表現した部分で、eが複雑な式の場合がうまく書けてないので、コンパクトに書けずにいます。
#!/usr/bin/env ruby class Machine def initialize(state) @pos = 0 @init = @state = state end def step(str) next_states(@state).#tap{|a| puts a.inspect}. each do|s| if s.type == :start @state = s.out1 return elsif s.type == :end @state = s return elsif s.b == str[@pos] s.exec(@pos, str) @state = s.out1 @pos += s.steps return end end raise "failed" end def exec(str) while @state.type != :end step(str) end @state = @init @pos = 0 str end def next_states(state) nstates = [] return [] if !state case state.type when :split nstates << next_states(state.out1) nstates << next_states(state.out2) else nstates << state end nstates.flatten.compact end end class State attr_reader :b, :steps, :type, :a, :id attr_accessor :out1, :out2 def initialize(id, type, b, a, steps) @id = id @type = type @b = b @a = a @steps = steps end def inspect "S(#{@id}, #{@type}, #{@b.inspect}, #{@a.inspect})" end def to_s "S(#{@id},#{@b},#{@a})" end def exec(i, str) #puts "S(#{@id}).exec(#{i}, #{str})" str[i] = @a end def push(o) s = self while s.out1 != nil do s = s.out1 end s.out1 = o end end def star(id, before, after, step) s1 = State.new(id, :split, nil, nil, 1) s2 = State.new("#{id}:star", :value, before, after, step) s1.out2 = s2 s2.out1 = s1 s1 end def connect(s1, before, after, step, s2) s3 = State.new("#{s1.id}:#{s2.id}", :value, before, after, step) s = s1 while s do if !s.out1 s.out1 = s3 break elsif s1.out1.type == :value s4 = State.new("", :split, nil, nil, nil) t = s.out1 s.out1 = s4 s4.out1 = t s4.out2 = s3 break end s = s.out2 end s3.out1 = s2 end def rich_and_poor rich = star(1, '0', '0', 1) poor = star(2, '0', '0', 1) goal = State.new(3, :end, nil, nil, nil) connect(rich, '1', '1', 1, poor) connect(rich, ' ', '0', 1, goal) connect(poor, '1', '1', 1, rich) connect(poor, ' ', '1', 1, goal) m = Machine.new(rich) puts "0101101" == m.exec("010110 ") puts "0000000" == m.exec("000000 ") puts "0001001" == m.exec("000100 ") end rich_and_poor
数独板をAsciiコードで表示するの作りました。
数独ソルバー作っていくときに、数列で1行でわっと表示したり、9文字ずつ改行するのとかでも、ちょっと見えにくいので、ぱっと見てわかる表示に変更しました。
もっと複雑な画面の場合、Jupyter Notebook使うしかなさそうです。今回もJupyter Notebookにした方が良かったです、多分。
ブロッケンで決まる一番自明な場合
上のような場合、灰色で塗りつぶしている部分(以下カーソルのある場所と言います)がブロッケンで決まるとすぐ分かるパターンです。このカーソルの位置のブロックの上下左右のブロック全てに2が含まれています。なので、これらの2でカーソルの位置のブロックで2が入れる場所は必ず1マスに限定されます。というわけで、ここのブロックが空ブロックでもこの状況では2がブロッケンで決まります。
SudokuLogの使い方(ゲスト向け)
現在、herokuで公開中のSudokuLogの使い方についてです。主にゲスト向けに操作方法のみ解説します。ログインユーザーとしては、いつどんな問題をどのように解いたのかを記録として残す機能がメインになりますが、ゲストとしては、数独解くのに使う紙と鉛筆の代わりのようなものです。初心者が数独を解くハードルをいくらか下げてくれるとは思います。
とりあえず使ってみる
ゲスト(ログインしていない状態)の方の場合、トップページを開くと、すでに数独が入力された状態から始まります。 [start]ボタンを押すと、ローディング終了後に数字が青に変わります。ここから数独を解いていくことができます。
新規数独の入力する場合
入力済み数独を削除 する
[clear]ボタンを押すと画面がクリアされます。
新規数独を入力する
数独の入力の仕方は矢印でカーソルを移動させて、数字を押すことでマスの数字が入ります。数字を取り消したいときは、カーソルを合わせて、そこに表示されている数字を入力すると空マスになり、他の数字を入れた場合は、その数字に切り替わります。
キーボードを使った操作
PCから使っている場合は、物理キーボードから操作できます。画面下のボタンは主にスマホから操作するときに使います。十字キーでもカーソル移動できますが、vimと同じようにも移動させることができます。
キー | 説明 |
1 2 3 4 5 6 7 8 9 | fixモード時カーソルの位置に数字を入力。deleteモード時はメモからその数字を消す |
h | 左にカーソルを移動 |
← | 左にカーソルを移動 |
j | 下にカーソルを移動 |
↓ | 下にカーソルを移動 |
k | 上にカーソルを移動 |
↑ | 上にカーソルを移動 |
l | 右にカーソルを移動 |
→ | 右にカーソルを移動 |
u | 1ステップ戻ります。間違えて入力した場合、この操作でのみ消せます |
r | アンドゥしたけどやっぱり戻したいとき、rを押すと戻れます。 |
天才になりたかったら「限界的練習」を身に付けようってことでWebアプリ作りました
『超一流になるのは才能か努力か? (文春e-book)』によると、世の中の天才と呼ばれる人たちは「限界的練習」やそれに類するものを実践して、並の人では考えられないような能力を身につけているそうです。才能というものは、どうやら存在しないそうです。あったとしても、僕たちが聞かされたり、思い込んだりしている程にはないようです。僕たちが才能というものが存在すると信じて疑わなくなった原因は、スポーツや勉強などをはじめたときだと思います。特に説明しなくても、誰でも経験はあると思います。はじめて直ぐにその小学校の誰よりもうまくなったとか、逆に何年も続けているのに全くうまくならないとか。でも、この本で紹介されている調査によると、そういった個人差ごく初期のみにあらわれるもので、長続きはしないそうです。そういえば、器用になんでもある程度はこなすけれども、そこまでどれもうまくないって人もいますよね。
それでも「才能はない」なんて急に言われても、自分事として信じるってのは難しい話ですよね。だったら、この本の1章で事例として紹介されている短期記憶を驚異的に伸ばした事例を自分でも試してみたら良いと思ったんですね。その事例では短期記憶力を測定は、実験者が数列を1桁ずつ読み上げ、それを被験者が何桁まで復唱できるかを見ることでやってました。ルールの詳細は次のとおりです。
- 使用する数列はランダムとします。
- 実験者は毎秒1桁の速度で数字を読み上げます。
- はじめは5桁からはじめます。
- 被験者が正しく復唱できた場合は1桁ずつ増やしていきます
- 被験者が間違えた場合は2桁ずつ減らします。
通常、人間が短期記憶を使って記憶できる桁数は7桁前後です。ところがこの事例で被験者は、2年間で82桁まで記録を伸ばしたそうです。ちょっと信じられないですよね。どのくらいの頻度で、1度にどれだけの時間練習したのかは正確には分からないのですが、簡単に試せるならば自分でもちょっと試したくなりました。人力でやるとなると、実験に協力してくれる人(数字を読み上げ、合っているか記録する人)がいるし、ランダムな数列を事前に用意したり、正しく復唱できているか判定するのも面倒だし、時間がかかります。
ということで「短期記憶チャレンジ」というWebアプリを作りました。ChromeのPC版とAndroid版で動作確認してます。測定結果はtwitterのシェアボタンで投稿するか、どこかにメモして記録します。使い方は次の動画でも確認できますよ。
ActivityにonTouchEventを書く時の注意
Viewに書いていたonTouchEventをActivityに書くように変更すると、y軸の値がおかしくなる場合があります。調査すると、ViewのonTouchEventの中のevent.getRawY()はViewの座標を基準に計算しますが、Activityはscreenサイズで計算するようです。そのため、下の図のようにフルスクリーンモードでない場合はActivityにonTouchEventをそのまま移すと動作がおかしくなります。
これを直すには、下の図のようにフルスクリーンモード(バッテリー残量などの部分が消える)にするか、screenの高さとviewの高さの差をy軸の値に足す必要があります。
このような面倒があるので、通常はViewの方へonTouchEventは書いた方が良いかもしれません。ただ、onTouchEventに対して、ロジックを変更するようなコードを書くので、Viewにロジックが混ぜないことを徹底するならば、Activityの方へ書くべきかもしれません。
フルスクリーンモードにする方法について
「タイトルバーを消す方法」を参考にしました。
Ruby on Railsでコンポジットパターン
FileEntryはbodyを持ち、DirectoryEntryはentriesを持つ。sizeはFileEntryの場合は、body#sizeを返し、DirectoryEntryはentriesのsizeの和を返す。