tortoise 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.swp
2
+ .DS_Store
3
+ *.gem
4
+ .bundle
5
+ Gemfile.lock
6
+ pkg/*
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in tortoise.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,136 @@
1
+ Tortoise [![Build Status](https://secure.travis-ci.org/huntca/tortoise.png)](http://travis-ci.org/huntca/tortoise)
2
+ ========
3
+ [logo]: http://en.wikipedia.org/wiki/Logo_(programming_language) "Logo Programming Language"
4
+ [rubygems]: https://rubygems.org/ "Rubygems"
5
+
6
+ Tortoise is a [Logo][logo] interpreter for Ruby. To demonstrate the
7
+ awesomeness of Logo, we'll draw a ruby! This example can be found in the
8
+ repository at `spec/data/simple.logo`.
9
+
10
+ > Tortoise::Interpreter.new <<-LOGO
11
+ 61
12
+ RT 135
13
+ FD 5
14
+ REPEAT 2 [ RT 90 FD 15 ]
15
+ RT 90
16
+ FD 5
17
+ RT 45
18
+ FD 20
19
+ LOGO
20
+
21
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
+ . . . . . . X X X X X X X X X X X X X X X X X X X X X . . . . . .
23
+ . . . . . X . . . . . . . . . . . . . . . . . . . . . X . . . . .
24
+ . . . . X . . . . . . . . . . . . . . . . . . . . . . . X . . . .
25
+ . . . X . . . . . . . . . . . . . . . . . . . . . . . . . X . . .
26
+ . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . X . .
27
+ . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . X .
28
+ . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . X . .
29
+ . . . X . . . . . . . . . . . . . . . . . . . . . . . . . X . . .
30
+ . . . . X . . . . . . . . . . . . . . . . . . . . . . . X . . . .
31
+ . . . . . X . . . . . . . . . . . . . . . . . . . . . X . . . . .
32
+ . . . . . . X . . . . . . . . . . . . . . . . . . . X . . . . . .
33
+ . . . . . . . X . . . . . . . . . . . . . . . . . X . . . . . . .
34
+ . . . . . . . . X . . . . . . . . . . . . . . . X . . . . . . . .
35
+ . . . . . . . . . X . . . . . . . . . . . . . X . . . . . . . . .
36
+ . . . . . . . . . . X . . . . . . . . . . . X . . . . . . . . . .
37
+ . . . . . . . . . . . X . . . . . . . . . X . . . . . . . . . . .
38
+ . . . . . . . . . . . . X . . . . . . . X . . . . . . . . . . . .
39
+ . . . . . . . . . . . . . X . . . . . X . . . . . . . . . . . . .
40
+ . . . . . . . . . . . . . . X . . . X . . . . . . . . . . . . . .
41
+ . . . . . . . . . . . . . . . X . X . . . . . . . . . . . . . . .
42
+ . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . .
43
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
+
45
+ Installation
46
+ ------------
47
+ Tortoise is available on [rubygems.org][rubygems]. To install, add
48
+ `gem tortoise` to your `Gemfile` or install manually with:
49
+
50
+ gem install tortoise
51
+
52
+ Usage
53
+ -----
54
+ To use Tortoise, create an instance of `Tortoise::Interpreter` and execute
55
+ any of the supported Logo commands.
56
+
57
+ # specify canvas size for this drawing
58
+ canvas_size = 11
59
+ interpreter = Tortoise::Interpreter.new(canvas_size)
60
+
61
+ # execute any supported commands
62
+ interpreter.rt(90)
63
+ interpreter.fd(3)
64
+ interpreter.lt(45)
65
+ interpreter.bk(4)
66
+
67
+ Tortoise also accepts commands as an input string:
68
+
69
+ interpreter = Tortoise::Interpreter.new(11)
70
+ interpreter.draw "RT 90"
71
+ interpreter.draw "FD 3"
72
+ interpreter.draw "LT 45"
73
+ interpreter.draw "BK 4"
74
+
75
+ You can execute entire blocks of commands at once:
76
+
77
+ interpreter = Tortoise::Interpreter.new(61)
78
+
79
+ interpreter.draw <<-STEPS
80
+ RT 135
81
+ FD 5
82
+ REPEAT 2 [ RT 90 FD 15 ]
83
+ RT 90
84
+ FD 5
85
+ RT 45
86
+ FD 20
87
+ STEPS
88
+
89
+ Finally, commands can be executed when a `Tortoise::Interpreter` is
90
+ instantiated. The command string must contain the canvas size in the
91
+ first line. This is most useful when reading commands from a file.
92
+ Assume we have the file `drawing.logo`:
93
+
94
+ 61
95
+ RT 135
96
+ FD 5
97
+ REPEAT 2 [ RT 90 FD 15 ]
98
+ RT 90
99
+ FD 5
100
+ RT 45
101
+ FD 20
102
+
103
+ We can load and execute `drawing.logo` with:
104
+
105
+ file = File.new('drawing.logo')
106
+ tortoise = Tortoise::Interpreter.new(file.read)
107
+
108
+ Command Line Usage
109
+ ------------------
110
+ Tortoise can be used on the command line to render logo command files. The
111
+ output is rendered to standard out.
112
+
113
+ Usage: tortoise [FILE]
114
+
115
+ For example, if you'd like to render `drawing.logo` to `drawing.txt`:
116
+
117
+ $ tortoise drawing.logo > drawing.txt
118
+
119
+ Rendering The Canvas
120
+ --------------------
121
+ Tortoise can currently render its canvas to a string. Html export is planned
122
+ soon (which will allow a very high resolution canvas). To get a string
123
+ representation of the current canvas:
124
+
125
+ interpreter = Tortoise::Interpreter.new(5)
126
+ interpreter.to_s
127
+
128
+ Supported Commands
129
+ ------------------
130
+ Tortoise only supports a small subset of all [Logo][logo] commands.
131
+
132
+ - `RT x`: Turn the tortoise `x` degrees to the right (increments of 45)
133
+ - `LT x`: Turn the tortoise `x` degrees to the right (increments of 45)
134
+ - `FD x`: Move the tortoise `x` steps forward
135
+ - `BK x`: Move the tortoise `x` steps backward
136
+ - `REPEAT n [ x ]`: Repeat commands `x` a total of `n` times
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc 'Default: Run all specs'
5
+ task :default => :spec
6
+
7
+ desc 'Run all specs'
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.rspec_opts = ['--color']
10
+ end
data/bin/tortoise ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ $:.push File.expand_path("../../lib", __FILE__)
3
+ require 'tortoise/interpreter'
4
+
5
+ if ARGV.size < 1
6
+ puts "Usage: tortoise [FILE]"
7
+ raise Exception.new("Missing filename")
8
+ end
9
+
10
+ commands = File.new(ARGV.first).read
11
+ puts Tortoise::Interpreter.new(commands).to_s
@@ -0,0 +1,123 @@
1
+ module Tortoise
2
+ class Interpreter
3
+ attr_reader :size, :position, :direction, :canvas
4
+
5
+ def initialize(instructions)
6
+ lines = instructions.to_s.split("\n")
7
+
8
+ @size = lines.shift.to_i
9
+ @canvas = new_canvas
10
+ @direction = 0
11
+ center = (@size - @size/2) - 1
12
+
13
+ update_position(center, center)
14
+ draw(lines)
15
+ end
16
+
17
+ def rt(degrees)
18
+ rotate(degrees)
19
+ end
20
+
21
+ def lt(degrees)
22
+ rotate(-degrees)
23
+ end
24
+
25
+ def fd(steps)
26
+ walk(steps)
27
+ end
28
+
29
+ def bk(steps)
30
+ walk(-steps)
31
+ end
32
+
33
+ def draw(commands)
34
+ commands = commands.split("\n") if commands.respond_to?(:split)
35
+ commands.each { |command| execute(command) }
36
+ end
37
+
38
+ def to_s
39
+ s = ''
40
+ oriented_canvas.each do |column|
41
+ column.each do |pixel|
42
+ char = pixel ? 'X' : '.'
43
+ s += "#{char} "
44
+ end
45
+ s = s.strip + "\n"
46
+ end
47
+ s
48
+ end
49
+
50
+ private
51
+
52
+ def new_canvas
53
+ Array.new(@size) { Array.new(@size) {false} }
54
+ end
55
+
56
+ def update_position(x, y)
57
+ @position = place_in_canvas_bounds(x, y)
58
+ update_canvas
59
+ end
60
+
61
+ def rotate(degrees)
62
+ @direction += degrees
63
+ @direction += 360 while @direction < 0
64
+ @direction -= 360 while @direction >= 360
65
+ end
66
+
67
+ def execute(command)
68
+ words = command.split(' ')
69
+ if words.size == 2
70
+ method, param = words
71
+ self.send(method.downcase, param.to_i)
72
+ else
73
+ 1.upto(words[1].to_i) do
74
+ commands = words[3..words.size-2]
75
+ execute(commands.shift(2).join(' ')) while commands.size > 0
76
+ end
77
+ end
78
+ end
79
+
80
+ def walk(steps)
81
+ x, y = @position
82
+ step = steps < 0 ? -1 : 1
83
+ steps = steps < 0 ? -steps : steps
84
+
85
+ 1.upto(steps) do
86
+ x, y = case direction
87
+ when 0; [x, y + step]
88
+ when 45; [x + step, y + step]
89
+ when 90; [x + step, y ]
90
+ when 135; [x + step, y - step]
91
+ when 180; [x, y - step]
92
+ when 225; [x - step, y - step]
93
+ when 270; [x - step, y ]
94
+ when 315; [x - step, y + step]
95
+ end
96
+ update_position(x, y)
97
+ end
98
+ end
99
+
100
+ def update_canvas
101
+ x, y = @position
102
+ @canvas[x][y] = true
103
+ end
104
+
105
+ def place_in_canvas_bounds(x, y)
106
+ x = 0 if x < 0
107
+ y = 0 if y < 0
108
+ x = @size - 1 if x >= @size
109
+ y = @size - 1 if y >= @size
110
+ [x, y]
111
+ end
112
+
113
+ def oriented_canvas
114
+ oriented = new_canvas
115
+ @canvas.each_with_index do |column, i|
116
+ column.each_with_index do |pixel, j|
117
+ oriented[@size-1-j][i] = pixel
118
+ end
119
+ end
120
+ oriented
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,3 @@
1
+ module Tortoise
2
+ VERSION = "0.8.0"
3
+ end
data/lib/tortoise.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'tortoise/interpreter'
2
+ require 'tortoise/version'
@@ -0,0 +1,3 @@
1
+ 1001
2
+
3
+ REPEAT 4 [ FD 200 LT 45 FD 100 LT 45 FD 50 LT 45 FD 25 LT 45 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 RT 90 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 LT 45 BK 25 RT 90 FD 25 LT 45 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 RT 90 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 LT 45 BK 25 LT 45 BK 50 RT 90 FD 50 LT 45 FD 25 LT 45 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 RT 90 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 LT 45 BK 25 RT 90 FD 25 LT 45 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 RT 90 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 LT 45 BK 25 LT 45 BK 50 LT 45 BK 100 RT 90 FD 100 LT 45 FD 50 LT 45 FD 25 LT 45 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 RT 90 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 LT 45 BK 25 RT 90 FD 25 LT 45 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 RT 90 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 LT 45 BK 25 LT 45 BK 50 RT 90 FD 50 LT 45 FD 25 LT 45 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 RT 90 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 LT 45 BK 25 RT 90 FD 25 LT 45 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 RT 90 FD 12 LT 45 FD 6 LT 45 RT 90 LT 45 BK 6 RT 90 FD 6 LT 45 RT 90 LT 45 BK 6 LT 45 BK 12 LT 45 BK 25 LT 45 BK 50 LT 45 BK 100 LT 45 BK 200 RT 90 ]
@@ -0,0 +1,9 @@
1
+ 61
2
+
3
+ RT 135
4
+ FD 5
5
+ REPEAT 2 [ RT 90 FD 15 ]
6
+ RT 90
7
+ FD 5
8
+ RT 45
9
+ FD 20
@@ -0,0 +1,61 @@
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
+ . . . . . . . . . . X X X X X X X X X X X X X X X X X X X X X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
+ . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
+ . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
+ . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
+ . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . .
36
+ . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . .
37
+ . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . .
38
+ . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
+ . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
+ . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
+ . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
+ . . . . . . . . . . . X . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
+ . . . . . . . . . . . . X . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
+ . . . . . . . . . . . . . X . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
+ . . . . . . . . . . . . . . X . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
+ . . . . . . . . . . . . . . . X . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
+ . . . . . . . . . . . . . . . . X . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
+ . . . . . . . . . . . . . . . . . X . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
+ . . . . . . . . . . . . . . . . . . X . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
+ . . . . . . . . . . . . . . . . . . . X . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
+ . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -0,0 +1,10 @@
1
+ require 'tortoise'
2
+
3
+ describe Tortoise::Interpreter do
4
+ it 'produces the expected string output' do
5
+ input = File.new('./spec/data/simple.logo').read
6
+ output = File.new('./spec/data/simple_out.txt').read
7
+
8
+ Tortoise::Interpreter.new(input).to_s.should == output
9
+ end
10
+ end
@@ -0,0 +1,467 @@
1
+ require 'tortoise/interpreter'
2
+
3
+ describe Tortoise::Interpreter do
4
+ let(:tortoise) { Tortoise::Interpreter.new(11) }
5
+
6
+ it 'can be initialized with a canvas size' do
7
+ tortoise = Tortoise::Interpreter.new(11)
8
+ tortoise.size.should == 11
9
+ end
10
+
11
+ it 'can be initialized with instructions' do
12
+ instructions = <<-STEPS
13
+ 5
14
+
15
+ REPEAT 2 [ RT 45 ]
16
+ FD 1
17
+ STEPS
18
+
19
+ tortoise = Tortoise::Interpreter.new(instructions)
20
+ tortoise.size.should == 5
21
+ tortoise.direction.should == 90
22
+ tortoise.position.should == [3, 2]
23
+ end
24
+
25
+ it 'starts with a single marked pixel on the canvas' do
26
+ count = 0
27
+ tortoise.canvas.each do |column|
28
+ column.each { |pixel| count += 1 if pixel }
29
+ end
30
+ count.should == 1
31
+ end
32
+
33
+ it 'defaults tortoise position to the center of the canvas' do
34
+ tortoise.position.should == [5, 5]
35
+ end
36
+
37
+ it 'defaults tortoise direction to zero degrees (up)' do
38
+ tortoise.direction.should == 0
39
+ end
40
+
41
+ describe '#draw' do
42
+ it 'draws the image on the canvas when given a string' do
43
+ tortoise = Tortoise::Interpreter.new(5)
44
+ tortoise.draw <<-STEPS
45
+ RT 90
46
+ FD 1
47
+ REPEAT 2 [ RT 45 ]
48
+ FD 2
49
+ REPEAT 2 [ LT 45 ]
50
+ FD 1
51
+ RT 180
52
+ FD 2
53
+ STEPS
54
+
55
+ tortoise.canvas.should == [
56
+ [false, false, false, false, false],
57
+ [false, false, false, false, false],
58
+ [true , false, true , false, false],
59
+ [true , true , true , false, false],
60
+ [true , false, false, false, false]]
61
+ end
62
+
63
+ it 'draws the image on the canvas when given an array' do
64
+ tortoise = Tortoise::Interpreter.new(5)
65
+ tortoise.draw([
66
+ 'RT 90',
67
+ 'FD 1',
68
+ 'REPEAT 2 [ RT 45 ]',
69
+ 'FD 2',
70
+ 'REPEAT 2 [ LT 45 ]',
71
+ 'FD 1',
72
+ 'RT 180',
73
+ 'FD 2'])
74
+ tortoise.canvas.should == [
75
+ [false, false, false, false, false],
76
+ [false, false, false, false, false],
77
+ [true , false, true , false, false],
78
+ [true , true , true , false, false],
79
+ [true , false, false, false, false]]
80
+ end
81
+ end
82
+
83
+ describe '#to_s' do
84
+ it 'renders canvas to string' do
85
+ tortoise = Tortoise::Interpreter.new(5)
86
+ tortoise.draw <<-STEPS
87
+ RT 90
88
+ FD 1
89
+ REPEAT 2 [ RT 45 ]
90
+ FD 2
91
+ REPEAT 2 [ LT 45 ]
92
+ FD 1
93
+ RT 180
94
+ FD 2
95
+ STEPS
96
+
97
+ tortoise.to_s.should == "" +
98
+ ". . . . .\n" +
99
+ ". . . . .\n" +
100
+ ". . X X .\n" +
101
+ ". . . X .\n" +
102
+ ". . X X X\n"
103
+ end
104
+ end
105
+
106
+ describe '#rt' do
107
+ it 'can rotate the tortoise 45 degrees to the right' do
108
+ tortoise.rt(45)
109
+ tortoise.direction.should == 45
110
+ end
111
+
112
+ it 'can rotate the tortoise 360 degrees to the right' do
113
+ tortoise.rt(360)
114
+ tortoise.direction.should == 0
115
+ end
116
+
117
+ it 'can rotate the tortoise 495 degrees to the right' do
118
+ tortoise.rt(495)
119
+ tortoise.direction.should == 135
120
+ end
121
+
122
+ it 'can rotate the tortoise 810 degrees to the right' do
123
+ tortoise.rt(810)
124
+ tortoise.direction.should == 90
125
+ end
126
+
127
+ it 'can rotate the tortoise multiple times' do
128
+ tortoise.rt(90)
129
+ tortoise.rt(45)
130
+ tortoise.direction.should == 135
131
+ end
132
+ end
133
+
134
+ describe '#lt' do
135
+ it 'can rotate the tortoise 45 degrees to the left' do
136
+ tortoise.lt(45)
137
+ tortoise.direction.should == 315
138
+ end
139
+
140
+ it 'can rotate the tortoise 360 degrees to the left' do
141
+ tortoise.lt(360)
142
+ tortoise.direction.should == 0
143
+ end
144
+
145
+ it 'can rotate the tortoise 495 degrees to the left' do
146
+ tortoise.lt(495)
147
+ tortoise.direction.should == 225
148
+ end
149
+
150
+ it 'can rotate the tortoise 810 degrees to the left' do
151
+ tortoise.lt(810)
152
+ tortoise.direction.should == 270
153
+ end
154
+
155
+ it 'can rotate the tortoise multiple times' do
156
+ tortoise.lt(90)
157
+ tortoise.lt(45)
158
+ tortoise.direction.should == 225
159
+ end
160
+ end
161
+
162
+ describe '#rotate' do
163
+ it 'can rotate the tortoise 45 degrees' do
164
+ tortoise.send(:rotate, 45)
165
+ tortoise.direction.should == 45
166
+ end
167
+
168
+ it 'can rotate the tortoise 90 degrees' do
169
+ tortoise.send(:rotate, 90)
170
+ tortoise.direction.should == 90
171
+ end
172
+
173
+ it 'can rotate the tortoise 360 degrees' do
174
+ tortoise.send(:rotate, 360)
175
+ tortoise.direction.should == 0
176
+ end
177
+
178
+ it 'can rotate the tortoise 495 degrees' do
179
+ tortoise.send(:rotate, 495)
180
+ tortoise.direction.should == 135
181
+ end
182
+
183
+ it 'can rotate the tortoise 810 degrees' do
184
+ tortoise.send(:rotate, 810)
185
+ tortoise.direction.should == 90
186
+ end
187
+
188
+ it 'can rotate the tortoise -45 degrees' do
189
+ tortoise.send(:rotate, -45)
190
+ tortoise.direction.should == 315
191
+ end
192
+
193
+ it 'can rotate the tortoise -90 degrees' do
194
+ tortoise.send(:rotate, -90)
195
+ tortoise.direction.should == 270
196
+ end
197
+
198
+ it 'can rotate the tortoise -360 degrees' do
199
+ tortoise.send(:rotate, -360)
200
+ tortoise.direction.should == 0
201
+ end
202
+
203
+ it 'can rotate the tortoise -495 degrees' do
204
+ tortoise.send(:rotate, -495)
205
+ tortoise.direction.should == 225
206
+ end
207
+
208
+ it 'can rotate the tortoise -810 degrees' do
209
+ tortoise.send(:rotate, -810)
210
+ tortoise.direction.should == 270
211
+ end
212
+
213
+ it 'can rotate the tortoise multiple times' do
214
+ tortoise.send(:rotate, 90)
215
+ tortoise.send(:rotate, 45)
216
+ tortoise.direction.should == 135
217
+ end
218
+ end
219
+
220
+ describe '#fd' do
221
+ it 'moves the tortoise forward when facing 0 degress' do
222
+ x, y = tortoise.position
223
+ tortoise.fd(2)
224
+ tortoise.position.should == [x, y + 2]
225
+ end
226
+
227
+ it 'moves the tortoise forward when facing 45 degress' do
228
+ x, y = tortoise.position
229
+ tortoise.rt(45)
230
+ tortoise.fd(2)
231
+ tortoise.position.should == [x + 2, y + 2]
232
+ end
233
+
234
+ it 'moves the tortoise forward when facing 90 degress' do
235
+ x, y = tortoise.position
236
+ tortoise.rt(90)
237
+ tortoise.fd(2)
238
+ tortoise.position.should == [x + 2, y]
239
+ end
240
+
241
+ it 'moves the tortoise forward when facing 135 degress' do
242
+ x, y = tortoise.position
243
+ tortoise.rt(135)
244
+ tortoise.fd(2)
245
+ tortoise.position.should == [x + 2, y - 2]
246
+ end
247
+
248
+ it 'moves the tortoise forward when facing 180 degress' do
249
+ x, y = tortoise.position
250
+ tortoise.rt(180)
251
+ tortoise.fd(2)
252
+ tortoise.position.should == [x, y - 2]
253
+ end
254
+
255
+ it 'moves the tortoise forward when facing 225 degress' do
256
+ x, y = tortoise.position
257
+ tortoise.rt(225)
258
+ tortoise.fd(2)
259
+ tortoise.position.should == [x - 2, y - 2]
260
+ end
261
+
262
+ it 'moves the tortoise forward when facing 270 degress' do
263
+ x, y = tortoise.position
264
+ tortoise.rt(270)
265
+ tortoise.fd(2)
266
+ tortoise.position.should == [x - 2, y]
267
+ end
268
+
269
+ it 'moves the tortoise forward when facing 315 degress' do
270
+ x, y = tortoise.position
271
+ tortoise.rt(315)
272
+ tortoise.fd(2)
273
+ tortoise.position.should == [x - 2, y + 2]
274
+ end
275
+
276
+ it 'stops when it reaches the top of the canvas' do
277
+ tortoise.fd(100)
278
+ x, y = tortoise.position
279
+ y.should < tortoise.size
280
+ end
281
+
282
+ it 'stops when it reaches the bottom of the canvas' do
283
+ tortoise.rt(180)
284
+ tortoise.fd(100)
285
+ x, y = tortoise.position
286
+ y.should >= 0
287
+ end
288
+
289
+ it 'stops when it reaches the right of the canvas' do
290
+ tortoise.rt(90)
291
+ tortoise.fd(100)
292
+ x, y = tortoise.position
293
+ x.should < tortoise.size
294
+ end
295
+
296
+ it 'stops when it reaches the left of the canvas' do
297
+ tortoise.rt(270)
298
+ tortoise.fd(100)
299
+ x, y = tortoise.position
300
+ x.should >= 0
301
+ end
302
+
303
+ it 'draws on traveled areas of the canvas' do
304
+ tortoise = Tortoise::Interpreter.new(5)
305
+ tortoise.rt(90)
306
+ tortoise.fd(1)
307
+ tortoise.rt(90)
308
+ tortoise.fd(2)
309
+ tortoise.lt(90)
310
+ tortoise.fd(1)
311
+ tortoise.rt(180)
312
+ tortoise.fd(2)
313
+ tortoise.canvas.should == [
314
+ [false, false, false, false, false],
315
+ [false, false, false, false, false],
316
+ [true , false, true , false, false],
317
+ [true , true , true , false, false],
318
+ [true , false, false, false, false]]
319
+ end
320
+ end
321
+
322
+ describe '#bk' do
323
+ it 'moves the tortoise forward when facing 0 degress' do
324
+ x, y = tortoise.position
325
+ tortoise.bk(2)
326
+ tortoise.position.should == [x, y - 2]
327
+ end
328
+
329
+ it 'moves the tortoise forward when facing 45 degress' do
330
+ x, y = tortoise.position
331
+ tortoise.rt(45)
332
+ tortoise.bk(2)
333
+ tortoise.position.should == [x - 2, y - 2]
334
+ end
335
+
336
+ it 'moves the tortoise forward when facing 90 degress' do
337
+ x, y = tortoise.position
338
+ tortoise.rt(90)
339
+ tortoise.bk(2)
340
+ tortoise.position.should == [x - 2, y]
341
+ end
342
+
343
+ it 'moves the tortoise forward when facing 135 degress' do
344
+ x, y = tortoise.position
345
+ tortoise.rt(135)
346
+ tortoise.bk(2)
347
+ tortoise.position.should == [x - 2, y + 2]
348
+ end
349
+
350
+ it 'moves the tortoise forward when facing 180 degress' do
351
+ x, y = tortoise.position
352
+ tortoise.rt(180)
353
+ tortoise.bk(2)
354
+ tortoise.position.should == [x, y + 2]
355
+ end
356
+
357
+ it 'moves the tortoise forward when facing 225 degress' do
358
+ x, y = tortoise.position
359
+ tortoise.rt(225)
360
+ tortoise.bk(2)
361
+ tortoise.position.should == [x + 2, y + 2]
362
+ end
363
+
364
+ it 'moves the tortoise forward when facing 270 degress' do
365
+ x, y = tortoise.position
366
+ tortoise.rt(270)
367
+ tortoise.bk(2)
368
+ tortoise.position.should == [x + 2, y]
369
+ end
370
+
371
+ it 'moves the tortoise forward when facing 315 degress' do
372
+ x, y = tortoise.position
373
+ tortoise.rt(315)
374
+ tortoise.bk(2)
375
+ tortoise.position.should == [x + 2, y - 2]
376
+ end
377
+
378
+ it 'stops when it reaches the bottom of the canvas' do
379
+ tortoise.bk(100)
380
+ x, y = tortoise.position
381
+ y.should >= 0
382
+ end
383
+
384
+ it 'stops when it reaches the top of the canvas' do
385
+ tortoise.rt(180)
386
+ tortoise.bk(100)
387
+ x, y = tortoise.position
388
+ y.should < tortoise.size
389
+ end
390
+
391
+ it 'stops when it reaches the left of the canvas' do
392
+ tortoise.rt(90)
393
+ tortoise.bk(100)
394
+ x, y = tortoise.position
395
+ x.should >= 0
396
+ end
397
+
398
+ it 'stops when it reaches the right of the canvas' do
399
+ tortoise.rt(270)
400
+ tortoise.bk(100)
401
+ x, y = tortoise.position
402
+ x.should < tortoise.size
403
+ end
404
+
405
+ it 'draws on traveled areas of the canvas' do
406
+ tortoise = Tortoise::Interpreter.new(5)
407
+ tortoise.lt(90)
408
+ tortoise.bk(1)
409
+ tortoise.rt(90)
410
+ tortoise.bk(2)
411
+ tortoise.lt(90)
412
+ tortoise.bk(1)
413
+ tortoise.rt(180)
414
+ tortoise.bk(2)
415
+ tortoise.canvas.should == [
416
+ [false, false, false, false, false],
417
+ [false, false, false, false, false],
418
+ [true , false, true , false, false],
419
+ [true , true , true , false, false],
420
+ [true , false, false, false, false]]
421
+ end
422
+ end
423
+
424
+ describe '#execute' do
425
+ it 'can execute lowercase commands' do
426
+ tortoise.send(:execute, 'rt 90')
427
+ tortoise.direction.should == 90
428
+ end
429
+
430
+ it 'can execute right turns' do
431
+ tortoise.send(:execute, 'RT 90')
432
+ tortoise.direction.should == 90
433
+ end
434
+
435
+ it 'can execute left turns' do
436
+ tortoise.send(:execute, 'LT 90')
437
+ tortoise.direction.should == 270
438
+ end
439
+
440
+ it 'can execute forward steps' do
441
+ x, y = tortoise.position
442
+ tortoise.send(:execute, 'FD 3')
443
+ tortoise.position.should == [x, y + 3]
444
+ end
445
+
446
+ it 'can execute backward steps' do
447
+ x, y = tortoise.position
448
+ tortoise.send(:execute, 'BK 2')
449
+ tortoise.position.should == [x, y - 2]
450
+ end
451
+
452
+ it 'can execute single item repeat blocks' do
453
+ tortoise.send(:execute, 'REPEAT 2 [ RT 45 ]')
454
+ tortoise.direction.should == 90
455
+ end
456
+
457
+ it 'can execute multi-item repeat blocks' do
458
+ tortoise.send(:execute, 'REPEAT 2 [ RT 45 LT 90 ]')
459
+ tortoise.direction.should == 270
460
+ end
461
+
462
+ it 'can execute commands with extra whitespace' do
463
+ tortoise.send(:execute, ' RT 90 ')
464
+ tortoise.direction.should == 90
465
+ end
466
+ end
467
+ end
data/tortoise.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "tortoise/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "tortoise"
7
+ s.version = Tortoise::VERSION
8
+ s.authors = ["Chris Hunt"]
9
+ s.email = ["huntca@gmail.com"]
10
+ s.homepage = "https://github.com/huntca/tortoise"
11
+ s.summary = %q{Tortoise is a Logo interpreter for ruby.}
12
+ s.description = %q{Tortoise is a Logo interpreter for ruby.}
13
+
14
+ s.rubyforge_project = "tortoise"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_runtime_dependency "rest-client"
23
+
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "rspec"
26
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tortoise
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Hunt
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70316818801540 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70316818801540
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70316818793360 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70316818793360
36
+ description: Tortoise is a Logo interpreter for ruby.
37
+ email:
38
+ - huntca@gmail.com
39
+ executables:
40
+ - tortoise
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - .travis.yml
46
+ - Gemfile
47
+ - README.markdown
48
+ - Rakefile
49
+ - bin/tortoise
50
+ - lib/tortoise.rb
51
+ - lib/tortoise/interpreter.rb
52
+ - lib/tortoise/version.rb
53
+ - spec/data/complex.logo
54
+ - spec/data/simple.logo
55
+ - spec/data/simple_out.txt
56
+ - spec/integration/tortoise_integration_spec.rb
57
+ - spec/tortoise/interpreter_spec.rb
58
+ - tortoise.gemspec
59
+ homepage: https://github.com/huntca/tortoise
60
+ licenses: []
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project: tortoise
79
+ rubygems_version: 1.8.10
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Tortoise is a Logo interpreter for ruby.
83
+ test_files:
84
+ - spec/data/complex.logo
85
+ - spec/data/simple.logo
86
+ - spec/data/simple_out.txt
87
+ - spec/integration/tortoise_integration_spec.rb
88
+ - spec/tortoise/interpreter_spec.rb