#はじめに
前回brainf*ckの記事について書いてみたわけだが
文字だけだとわからないと思うので
ビジュアル的にプログラムが動いている様子がわかるプログラムを書くついでにRuby/Tkについて勉強してみた
#Ruby/Tkのインストール
Windowsの環境についてだけ説明します(他のOSはほかの記事を参考にしてみてください)
今回確認したrubyのバージョンは2.3です
- ActiveTclをこのサイトからダウンロード,インストールします**(このとき最新版の8.6ではなく,8.5.18.0をインストールすることに注意してください)**
- Rubyをインストールします,既にインストールしている人もそうでない人もRubyインストーラを起動して**「Tcl/Tkサポートをインストールする」にチェックを付けてインストールすればOK**みたいです
#実際に動かしてみる
test.rb
# 1
require 'tk'
# 2
test_btn = TkButton.new{
text 'test'
command { exit }
pack
}
# 3.
Tk.mainloop
##実行結果
このようなウィンドウがでてきて,ボタンを押すと消えます
##軽く解説
- ruby/tkを動かすためにはtkをrequireする必要があります
- ここでコンポーネントを配置していきます.ここではtest_btnというボタンを「"test"という文字」で「押すと終了する」ように作ってます.最後にpackで配置します
- 最終行にTk.mainloopと書くことで毎ループ動くことになります
#そんな感じで作ったのがこちら
brainfuck.rb
require 'tk'
#### SUMMARY ###############################################
## #
## array a is the stack values in i th command #
## and let p denote the pointer where the operating stack, #
## which is shown with red background in the GUI #
## str written in sourcel is a command in "main.bf" #
## and str2 shows the point which is p visibly #
## #
############################################################
a=[0,0,0,0,0,0,0,0]
str ="+++-->>+<+++[>+<-]>>>[>+<-]x"
str2="^ "
i=0
p=0
branket_stack=[]
#### Winodow area ####
window = TkRoot.new{
title 'Brainf*ck Visualizer'
resizable [0,0]
}
#### Registers area ####
regf = TkFrame.new{
relief 'sunken'
borderwidth 3
padx 15
pady 20
pack('side' => 'top')
}
f=[]
l=[]
8.times do |n|
f << TkFrame.new(regf){
relief 'sunken'
borderwidth 2
background ((p==n)?"red":"gray")
padx 10
pady 10
pack('side' => 'left')
}
l << TkLabel.new(f[n]){
text a[n]
pack
}
end
#### Script Area ####
scriptf = TkFrame.new(){
pack('side' => 'top')
}
sourcel = TkLabel.new(scriptf){
text str + "\n" + str2
font TkFont.new("family"=>"MS Mincho", "size"=>10)
pack('side' => 'left')
}
load_btn = TkButton.new{
text 'load'
command {
a.map!{0}
p=0
i=0
str=IO.read('main.bf')
str+='x'
str2=(str.size).times.map{" "}.join
str2[0]='^'
sourcel.text = str + "\n" + str2
8.times do |n|
l[n].text=a[n]
f[n].background ((p==n)?"red":"gray")
end
}
pack
}
next_btn = TkButton.new{
text 'next'
command proc{
if i==str.size
exit
else
case str[i]
when '+'
a[p]+=1
str2[i]=' '
i+=1
str2[i]='^'
sourcel.text = str + "\n" + str2
8.times do |i|
l[i].text = a[i]
end
when '-'
a[p]-=1
str2[i]=' '
i+=1
str2[i]='^'
sourcel.text = str + "\n" + str2
8.times do |i|
l[i].text = a[i]
end
when '>'
f[p].background="gray"
p+=1
f[p].background="red"
str2[i]=' '
i+=1
str2[i]='^'
sourcel.text = str + "\n" + str2
8.times do |i|
l[i].text = a[i]
end
when '<'
f[p].background="gray"
p-=1
f[p].background="red"
str2[i]=' '
i+=1
str2[i]='^'
sourcel.text = str + "\n" + str2
8.times do |i|
l[i].text = a[i]
end
when '['
if a[p] == 0
while str[i]!=']'
i+=1
end
else
branket_stack << i
i+=1
end
str2=(str.size).times.map{" "}.join
str2[i]='^'
sourcel.text = str + "\n" + str2
when ']'
if a[p] == 0
branket_stack.pop
i+=1
else
i=branket_stack.pop
end
str2=(str.size).times.map{" "}.join
str2[i]='^'
sourcel.text = str + "\n" + str2
end
end
}
pack
}
Tk.mainloop
##実行イメージ
このように今あるポインタとメモリ内の数字を見ながらワンステップずつ実行できます
また,loadボタンを押すことにより同じフォルダに保存したbrainf*ckのファイル"main.bf"を読み込むことができます
いつものことながら適当にしか作ってないので,メモリは8個という前提で[ ]の数合わせも確認しません,"."や","にも対応しません...
気が向いたら訂正します