tortoise 0.8.0

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/.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