-
Notifications
You must be signed in to change notification settings - Fork 0
/
bfm_state.rb
81 lines (80 loc) · 1.9 KB
/
bfm_state.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class BFMState
attr_reader :ary, :data_pos, :prog_pos
INSTS = "><+-[],.\0".bytes
def initialize(code, input=$stdin.each_byte, output=$stdout)
@ary = Hash.new(0)
code.each_byte.with_index {|ch,i| @ary[i] = ch}
@data_pos = 0
@prog_pos = 0
@visited_min = 0
@visited_max = code.bytes.length - 1
@input_enum = input
@output = output
end
def move_to_open
cnt = -1
while cnt != 0
@prog_pos -= 1
raise "Unmatch brackets" if @prog_pos < @visited_min
case @ary[@prog_pos]
when INSTS[4] then
cnt += 1
when INSTS[5] then
cnt -= 1
end
end
end
def move_to_close
cnt = 1
while cnt != 0
@prog_pos += 1
raise "Unmatch brackets" if @prog_pos > @visited_max
case @ary[@prog_pos]
when INSTS[4] then
cnt += 1
when INSTS[5] then
cnt -= 1
end
end
end
def step
case @ary[@prog_pos]
when INSTS[0] then
@data_pos += 1
@ary[@data_pos] = 0 if [email protected]_key?(@data_pos)
when INSTS[1] then
@data_pos -= 1
@ary[@data_pos] = 0 if [email protected]_key?(@data_pos)
when INSTS[2] then
if @ary[@data_pos] < 255 then
@ary[@data_pos] += 1
else
@ary[@data_pos] = 0
end
when INSTS[3] then
if @ary[@data_pos] > 0 then
@ary[@data_pos] -= 1
else
@ary[@data_pos] = 255
end
when INSTS[4] then
move_to_close if @ary[@data_pos] == 0
when INSTS[5] then
move_to_open if @ary[@data_pos] != 0
when INSTS[6] then
begin
@ary[@data_pos] = @input_enum.next
rescue StopIteration
@ary[@data_pos] = 0
end
when INSTS[7] then
@output.putc @ary[@data_pos].chr
when INSTS[8] then
return false
end
@prog_pos += 1
@visited_min = [@visited_min, @data_pos].min
@visited_max = [@visited_max, @data_pos].max
return true
end
end