Tsukuba.R#5で最後にちらっと発表したおまけ.RのanimationパッケージによるBrainf*ckのシミュレーション動画.
動画をダブルクリックしてはてなフォトライフにアクセスするとより大きいアニメーションが観られる.
この調子でこれからも役に立たないものを積極的に実装していきたい.
ソースは以下の通り.
# R de Brainf*ck library(grid) library(animation) brainfxxk <- function(code) { # local variables code <- strsplit(code,"")[[1]] len <- length(code) pc <- 1 ptr <- 1 mem <- rep(0, 128) output <- "" buf <- "" # > inc_ptr <- function() { ptr <<- ptr + 1 } # < dec_ptr <- function() { ptr <<- ptr - 1 } # + inc_mem <- function() { mem[ptr] <<- mem[ptr] + 1 } # - dec_mem <- function() { mem[ptr] <<- mem[ptr] - 1 } # . putc <- function() { output <<- paste(output, intToUtf8(mem[ptr]), sep="") } # , getc <- function() { if (nchar(buf) == 0) { buf <<- readline() } mem[ptr] <<- utf8ToInt(substring(buf, 1, 1)) buf <<- substring(buf, 2) } # [ wstart <- function() { if (mem[ptr] == 0) { count <- 1 pc <<- pc + 1 while (count > 0) { if (code[pc] == "[") { count <- count + 1; } if (code[pc] == "]") { count <- count - 1; } pc <<- pc + 1 } pc <<- pc - 1 } } # ] wend <- function() { if (mem[ptr] != 0) { count <- 1 pc <<- pc - 1 while (count > 0) { if (code[pc] == "[") { count <- count - 1; } if (code[pc] == "]") { count <- count + 1; } pc <<- pc - 1 } pc <<- pc + 1 } } # 描画用関数 plot_bf <- function() { grid.newpage() # memの枠 grid.lines(c(0.95, 0.1, 0.1, 0.95), c(0.7, 0.7, 0.8, 0.8)) sapply(seq(0.2, 0.9, 0.1), function(x) { grid.lines(x, c(0.7, 0.8)) }) grid.text("mem", 0.05, 0.75) # memのインデックスと内容 for (i in 1:8) { grid.text(i, 0.05 + 0.1 * i, 0.83) grid.text(mem[i], 0.05 + 0.1 * i, 0.75, gp=gpar(cex=2, col=ifelse(i==ptr, "red", "black"))) } # ptrの矢印 grid.arrows(0.05 + 0.1 * ptr, c(0.6, 0.68), gp=gpar(col="red")) # 次の命令 grid.text("next:", 0.46, 0.5) if (pc <= len) { grid.text(code[pc], 0.52, 0.505, gp=gpar(cex=2.5)) } # Brainf*ckのソース wl <- 32 hl <- 0.05 wc <- 0.02 grid.text("source:", 0.1, 0.4) if (pc <= len) { grid.rect(0.18 + 0.02 * ((pc-1) %% wl), 0.398 - hl * ((pc-1) %/% wl), 0.022, 0.04, gp=gpar(col="red")) } for (i in 1:len) { grid.text(code[i], 0.18 + 0.02 * ((i-1) %% wl), 0.4 - hl * ((i-1) %/% wl), gp=gpar(cex=1.25, fontfamily="Monaco", col=ifelse(i==pc, "red", "black"))) } # 出力 grid.text("output:", 0.1, 0.15) grid.text(output, 0.18, 0.15, gp=gpar(cex=2), just=("left")) } # main loop plot_bf() while (pc <= len) { switch(code[pc], ">" = inc_ptr(), "<" = dec_ptr(), "+" = inc_mem(), "-" = dec_mem(), "." = putc(), "," = getc(), "[" = wstart(), "]" = wend() ) pc <- pc + 1 plot_bf() } output } # Hello, world! hello <- "+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+." saveMovie(brainfxxk(hello), interval=0.08, moviename="hello", movietype="mpg", outdir=getwd(), width=640, height=480)
ポイント
- plot_bf()でBrainf*ckの処理系の状態を描画している
- 線や文字はグリッドグラフィックスを使って描画している
- ptr > 8の範囲の描画に対応していない
- Brainf*ckのソースの長さや出力の量が大きくなると表示がおかしくなる
- Brainf*ckのソースの描画にfor文を使いまくっているので非常に遅い
- Hello, world!くらいにしておけ
何の役にも立たないけど面白かった.