search
LoginSignup
0
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

Ruby/Tkを使ってBrainf*ckのプログラムを可視的にしてみた

はじめに

前回brainf*ckの記事について書いてみたわけだが
文字だけだとわからないと思うので
ビジュアル的にプログラムが動いている様子がわかるプログラムを書くついでにRuby/Tkについて勉強してみた

Ruby/Tkのインストール

Windowsの環境についてだけ説明します(他のOSはほかの記事を参考にしてみてください)
今回確認したrubyのバージョンは2.3です
1. ActiveTclをこのサイトからダウンロード,インストールします(このとき最新版の8.6ではなく,8.5.18.0をインストールすることに注意してください)
2. Rubyをインストールします,既にインストールしている人もそうでない人もRubyインストーラを起動して「Tcl/Tkサポートをインストールする」にチェックを付けてインストールすればOKみたいです

実際に動かしてみる

test.rb
# 1
require 'tk'

# 2
test_btn = TkButton.new{
  text 'test'
  command { exit }
  pack
}

# 3.
Tk.mainloop

実行結果

testwindow.png
このようなウィンドウがでてきて,ボタンを押すと消えます

軽く解説

  1. ruby/tkを動かすためにはtkをrequireする必要があります
  2. ここでコンポーネントを配置していきます.ここではtest_btnというボタンを「"test"という文字」で「押すと終了する」ように作ってます.最後にpackで配置します
  3. 最終行に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

実行イメージ

bfv.png
このように今あるポインタとメモリ内の数字を見ながらワンステップずつ実行できます
また,loadボタンを押すことにより同じフォルダに保存したbrainf*ckのファイル"main.bf"を読み込むことができます
いつものことながら適当にしか作ってないので,メモリは8個という前提で[ ]の数合わせも確認しません,"."や","にも対応しません...
気が向いたら訂正します

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0
Help us understand the problem. What are the problem?