rubyfunge 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+