rubyfunge 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in rubyfunge.gemspec
4
+ gemspec
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'rubyfunge/rubyfunge'
4
+ RubyFunge::RubyFunge.new.run_file(*ARGV)
@@ -0,0 +1,2 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+ require 'rubyfunge/rubyfunge'
@@ -0,0 +1,206 @@
1
+ module RubyFunge
2
+ class RubyFunge
3
+ attr_reader :x
4
+ attr_reader :y
5
+ attr_reader :stack
6
+ attr_reader :code
7
+
8
+ DIRS = [:left, :right, :up, :down]
9
+
10
+ def initialize()
11
+ @x, @y = 0, 0
12
+ @dir = :right
13
+ @code = []
14
+ @stack = []
15
+ @str_mode = false
16
+ @skip = false
17
+
18
+ @synt = {
19
+ '+'=>:op_add, '-'=>:op_sub, '*'=>:op_mul, '/'=>:op_div, '%'=>:op_mod,
20
+ '!'=>:op_not, '`'=>:op_gt,
21
+ '>'=>:op_right, '<'=>:op_left, '^'=>:op_up, 'v'=>:op_down,
22
+ '?'=>:op_rnd,
23
+ '_'=>:op_lr, '|'=>:op_ud,
24
+ '"'=>:op_str,
25
+ ':'=>:op_dup, '\\'=>:op_swp,
26
+ '$'=>:op_pop, '.'=>:op_outi, ','=>:op_outc,
27
+ '#'=>:op_skp, 'p'=>:op_put, 'g'=>:op_get,
28
+ '&'=>:op_aski, '~'=>:op_askc
29
+ }
30
+ end
31
+
32
+ def run_file(filename)
33
+ if (!File.exist?(filename))
34
+ raise "File does not exist"
35
+ else
36
+ run(File.open(filename).read())
37
+ end
38
+ end
39
+
40
+ def run(code)
41
+ i = 0
42
+ @code = []
43
+ code.each_line {|l|
44
+ @code[i] = l
45
+ i += 1
46
+ }
47
+ @x, @y = 0,0
48
+ while (@code[@y][@x].chr != '@')
49
+ op = @code[@y][@x].chr
50
+ if (@str_mode)
51
+ if (op == '"')
52
+ op_str
53
+ else
54
+ push op[0]
55
+ end
56
+ elsif (op=='#')
57
+ @skip = true
58
+ elsif (op=~/\d/ && !@skip)
59
+ self.send :push, op.to_i
60
+ @skip = false
61
+ else
62
+ self.send @synt[op] if @synt.include?(op) && !@skip
63
+ @skip = false
64
+ end
65
+ case @dir
66
+ when :right
67
+ @x += 1
68
+ @x = 0 if @x > @code[@y].length - 1
69
+ when :left
70
+ @x -= 1
71
+ @x = @code[@y].length - 1 if @x < 0
72
+ when :up
73
+ @y -= 1
74
+ @y = @code.length - 1 if @y < 0
75
+ when :down
76
+ @y += 1
77
+ @y = 0 if @y > @code.length - 1
78
+ end
79
+ end
80
+ end
81
+
82
+ # Instructions
83
+ private
84
+ def push(num)
85
+ @stack.push num
86
+ end
87
+
88
+ def op_right
89
+ @dir = :right
90
+ end
91
+
92
+ def op_down
93
+ @dir = :down
94
+ end
95
+
96
+ def op_up
97
+ @dir = :up
98
+ end
99
+
100
+ def op_left
101
+ @dir = :left
102
+ end
103
+
104
+ def op_pop
105
+ pop
106
+ end
107
+
108
+ def op_add
109
+ push pop+pop
110
+ end
111
+
112
+ def op_sub
113
+ push -pop+pop
114
+ end
115
+
116
+ def op_mul
117
+ push pop*pop
118
+ end
119
+
120
+ def op_div
121
+ a,b=pop,pop
122
+ if a == 0
123
+ push $stdin.readline.to_i
124
+ else
125
+ push b/a
126
+ end
127
+ end
128
+
129
+ def op_mod
130
+ a,b=pop,pop
131
+ if a == 0
132
+ push $stdin.readline.to_i
133
+ else
134
+ push b%a
135
+ end
136
+ end
137
+
138
+ def op_not
139
+ push pop == 0 ? 1 : 0
140
+ end
141
+
142
+ def op_gt
143
+ push pop <= pop ? 0 : 1
144
+ end
145
+
146
+ def op_rnd
147
+ @dir = DIRS[rand DIRS.length]
148
+ end
149
+
150
+ def op_lr
151
+ @dir = pop == 0 ? :right : :left
152
+ end
153
+
154
+ def op_ud
155
+ @dir = pop == 0 ? :down : :up
156
+ end
157
+
158
+ def op_str
159
+ @str_mode = !@str_mode
160
+ end
161
+
162
+ def op_dup
163
+ a = pop
164
+ push a; push a
165
+ end
166
+
167
+ def op_swp
168
+ a,b = pop, pop
169
+ push a; push b
170
+ end
171
+
172
+ def op_outi
173
+ print pop
174
+ end
175
+
176
+ def op_outc
177
+ print pop.chr
178
+ end
179
+
180
+ def op_get
181
+ y,x = pop, pop
182
+ push @code[x][y]
183
+ end
184
+
185
+ def op_put
186
+ v,y,x = pop, pop,pop
187
+ @code[x][y] = v.chr
188
+ end
189
+
190
+ def op_aski
191
+ c = $stdin.readline
192
+ push c.to_i
193
+ end
194
+
195
+ def op_askc
196
+ c = $stdin.getc
197
+ push c
198
+ end
199
+
200
+ private
201
+ def pop
202
+ return 0 if @stack.length == 0
203
+ @stack.pop
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,3 @@
1
+ module Rubyfunge
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/rubyfunge/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "rubyfunge"
6
+ s.version = Rubyfunge::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ['Zoltan Dezso']
9
+ s.email = ['dezso.zoltan@gmail.com']
10
+ s.homepage = "http://github.com/zaki/rubyfunge"
11
+ s.summary = "A Befunge-93 interpreter written in ruby."
12
+ s.description = "A Befunge-93 interpreter written in ruby."
13
+
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+ s.rubyforge_project = "rubyfunge"
16
+
17
+ s.add_development_dependency "bundler", ">= 1.0.0"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
21
+ s.require_path = 'lib'
22
+ end
@@ -0,0 +1,261 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'rubyfunge')
2
+ require "spec"
3
+ describe "RubyFunge" do
4
+ before(:each) do
5
+ @rbf = RubyFunge::RubyFunge.new
6
+ end
7
+
8
+ it "should go right" do
9
+ @rbf.run('>>>>>>>>>>@')
10
+ @rbf.x.should == 10
11
+ @rbf.y.should == 0
12
+ end
13
+
14
+ it "should go down" do
15
+ @rbf.run(
16
+ <<-EOS
17
+ v
18
+ @
19
+ EOS
20
+ )
21
+ @rbf.x.should == 0
22
+ @rbf.y.should == 1
23
+ end
24
+
25
+ it "should push numbers on the stack" do
26
+ @rbf.run('0123456789@')
27
+ @rbf.x.should == 10
28
+ @rbf.y.should == 0
29
+ @rbf.stack.should == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
30
+ end
31
+
32
+ it "should pop numbers from the stack" do
33
+ @rbf.run('0123456789$$$$$@')
34
+ @rbf.x.should == 15
35
+ @rbf.y.should == 0
36
+ @rbf.stack.should == [0, 1, 2, 3, 4]
37
+ end
38
+
39
+ it "should add numbers on the stack" do
40
+ @rbf.run('35+@')
41
+ @rbf.stack.should == [8]
42
+ end
43
+
44
+ it "should subtract numbers on the stack" do
45
+ @rbf.run('53-@')
46
+ @rbf.stack.should == [2]
47
+ end
48
+
49
+ it "should return 0 when stack is empty" do
50
+ @rbf.run('+@')
51
+ @rbf.stack.should == [0]
52
+ end
53
+
54
+ it "should multiply numbers on the stack" do
55
+ @rbf.run('35*@')
56
+ @rbf.stack.should == [15]
57
+ end
58
+
59
+ it "should divide numbers on the stack" do
60
+ @rbf.run('62/@')
61
+ @rbf.stack.should == [3]
62
+ end
63
+
64
+ it "should modulo divide numbers on the stack" do
65
+ @rbf.run('72%@')
66
+ @rbf.stack.should == [1]
67
+ end
68
+
69
+ it "should push result of not" do
70
+ @rbf.run('0!5!@')
71
+ @rbf.stack.should == [1, 0]
72
+ end
73
+
74
+ it "should push result of greater than" do
75
+ @rbf.run('91`19`@')
76
+ @rbf.stack.should == [0, 1]
77
+ end
78
+
79
+ it "should go in a random direction" do
80
+ @rbf.run(<<EOS
81
+ >v
82
+ ^?012@
83
+ ^<
84
+ EOS
85
+ )
86
+ @rbf.stack.should == [0, 1, 2]
87
+ end
88
+
89
+ it "should honor left-right selector" do
90
+ @rbf.run(<<EOS
91
+ 0_>>>>>v
92
+ @_1<<<<<
93
+ EOS
94
+ )
95
+ @rbf.stack.length.should == 0
96
+ end
97
+
98
+ it "should honor up-down selector" do
99
+ @rbf.run(<<EOS
100
+ 0|1@ >@
101
+ >>>>1|
102
+ >3@
103
+ EOS
104
+ )
105
+ @rbf.stack.length.should == 0
106
+ end
107
+
108
+ it "should start ascii mode" do
109
+ @rbf.run('"!dlrow ,olleH"123@')
110
+ @rbf.stack.should == 'Hello, world!'.reverse.split(//).map {|c| c[0]} + [1, 2, 3]
111
+ end
112
+
113
+ it "should duplicate values on the stack" do
114
+ @rbf.run('5:@')
115
+ @rbf.stack.should == [5, 5]
116
+ end
117
+
118
+ it "should swap values on the stack" do
119
+ @rbf.run('51\@')
120
+ @rbf.stack.should == [1, 5]
121
+ end
122
+
123
+ it "should print integer from stack" do
124
+ result = redirect_stdout do
125
+ @rbf.run('15.@')
126
+ end
127
+ result.should == '5'
128
+ end
129
+
130
+ it "should print string from stack" do
131
+ result = redirect_stdout do
132
+ @rbf.run('91+6*5+,@')
133
+ end
134
+ result.should == 'A'
135
+ end
136
+
137
+ it "should skip next instruction" do
138
+ @rbf.run('1#23#45#6@')
139
+ @rbf.stack.should == [1,3,5]
140
+ end
141
+
142
+ it "should skip next instruction and keep skipping if its also #" do
143
+ @rbf.run('1#2#3#4#5678@')
144
+ @rbf.stack.should == [1, 6, 7, 8]
145
+ end
146
+
147
+ it "should get value of program instruction" do
148
+ @rbf.run('09g@<<<<<0')
149
+ @rbf.stack.should == [48]
150
+ end
151
+
152
+ it "should put value of program instruction" do
153
+ @rbf.run('0991+6*5+p@<<<<<0')
154
+ @rbf.stack.should == []
155
+ @rbf.code[0][9].chr.should == 'A'
156
+ end
157
+
158
+ it "should ask the user for a number" do
159
+ redirect_stdin("0009") do
160
+ @rbf.run('01234&@')
161
+ @rbf.stack.should == [0, 1, 2, 3, 4, 9]
162
+ end
163
+ end
164
+
165
+ it "should ask the user for a character" do
166
+ redirect_stdin("ABCD") do
167
+ @rbf.run('01234~@')
168
+ @rbf.stack.should == [0, 1, 2, 3, 4, 65]
169
+ end
170
+ end
171
+
172
+ it "should solve fizzbuzz" do
173
+ code = <<-EOS
174
+ 55*4*v _ v )
175
+ v <>:1-:^ )
176
+ |:<$ < ,*48 < )
177
+ @>0"zzif">:#,_$ v )
178
+ >:3%!| >0"zzub">:#,_$^ )
179
+ >:5%!| )
180
+ v "buzz"0<>:. ^ )
181
+ |!%5: < )
182
+ >:#,_ $> ^)
183
+ EOS
184
+ result = redirect_stdout do
185
+ @rbf.run(code)
186
+ end
187
+
188
+ result.should == "1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz " +
189
+ "16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizzbuzz " +
190
+ "31 32 fizz 34 buzz fizz 37 38 fizz buzz 41 fizz 43 44 fizzbuzz " +
191
+ "46 47 fizz 49 buzz fizz 52 53 fizz buzz 56 fizz 58 59 fizzbuzz " +
192
+ "61 62 fizz 64 buzz fizz 67 68 fizz buzz 71 fizz 73 74 fizzbuzz 76 " +
193
+ "77 fizz 79 buzz fizz 82 83 fizz buzz 86 fizz 88 89 fizzbuzz 91 92 " +
194
+ "fizz 94 buzz fizz 97 98 fizz buzz "
195
+ end
196
+
197
+ it "should wrap around to the right" do
198
+ @rbf.run <<-EOS
199
+ >>v
200
+ 1@>>>
201
+ EOS
202
+ @rbf.stack.should == [1]
203
+ end
204
+
205
+ it "should wrap around to the left" do
206
+ @rbf.run <<-EOS
207
+ >>>>>>v
208
+ <<<<<<< @1
209
+ EOS
210
+ @rbf.stack.should == [1]
211
+ end
212
+
213
+ it "should wrap around at the bottom" do
214
+ @rbf.run <<-EOS
215
+ v1
216
+ v@
217
+ >v
218
+ v
219
+ v
220
+ EOS
221
+ @rbf.stack.should == [1]
222
+ end
223
+
224
+ it "should wrap around at the top" do
225
+ @rbf.run <<-EOS
226
+ ^
227
+ @
228
+ 1
229
+ EOS
230
+ @rbf.stack.should == [1]
231
+ end
232
+
233
+ it "should ask the user for a number when dividing by zero" do
234
+ redirect_stdin '5' do
235
+ @rbf.run('00/@')
236
+ @rbf.stack.should == [5]
237
+ end
238
+ end
239
+
240
+ it "should ask the user for a number when modulo dividing by zero" do
241
+ redirect_stdin '5' do
242
+ @rbf.run('00%@')
243
+ @rbf.stack.should == [5]
244
+ end
245
+ end
246
+
247
+ def redirect_stdout
248
+ oldstdout, $stdout = $stdout, StringIO.new
249
+ yield
250
+ $stdout.string
251
+ ensure
252
+ $stdout = oldstdout
253
+ end
254
+
255
+ def redirect_stdin(str)
256
+ oldstdin, $stdin = $stdin, StringIO.new(str)
257
+ yield
258
+ ensure
259
+ $stdin = oldstdin
260
+ end
261
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubyfunge
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Zoltan Dezso
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-19 00:00:00 +09:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: bundler
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
34
+ version: 1.0.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ description: A Befunge-93 interpreter written in ruby.
38
+ email:
39
+ - dezso.zoltan@gmail.com
40
+ executables:
41
+ - rubyfunge
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - Gemfile
48
+ - Rakefile
49
+ - bin/rubyfunge
50
+ - lib/rubyfunge.rb
51
+ - lib/rubyfunge/rubyfunge.rb
52
+ - lib/rubyfunge/version.rb
53
+ - rubyfunge.gemspec
54
+ - test/rubyfunge.spec
55
+ has_rdoc: true
56
+ homepage: http://github.com/zaki/rubyfunge
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 23
79
+ segments:
80
+ - 1
81
+ - 3
82
+ - 6
83
+ version: 1.3.6
84
+ requirements: []
85
+
86
+ rubyforge_project: rubyfunge
87
+ rubygems_version: 1.3.7
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: A Befunge-93 interpreter written in ruby.
91
+ test_files: []
92
+