straightedge 0.1.0 → 0.1.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +7 -0
- data/README.md +44 -2
- data/gemspec.yml +3 -0
- data/lib/straightedge.rb +33 -11
- data/lib/straightedge/aspects.rb +3 -0
- data/lib/straightedge/aspects/colorable.rb +8 -0
- data/lib/straightedge/aspects/figural.rb +12 -0
- data/lib/straightedge/aspects/positional.rb +10 -0
- data/lib/straightedge/colors.rb +72 -0
- data/lib/straightedge/config.rb +6 -0
- data/lib/straightedge/director.rb +39 -0
- data/lib/straightedge/extend/array.rb +2 -13
- data/lib/straightedge/figures.rb +8 -0
- data/lib/straightedge/{adapters.rb → figures/circle.rb} +0 -0
- data/lib/straightedge/figures/figure.rb +44 -0
- data/lib/straightedge/figures/grid.rb +65 -0
- data/lib/straightedge/figures/grid_cell.rb +0 -0
- data/lib/straightedge/figures/hexagon.rb +33 -0
- data/lib/straightedge/figures/label.rb +13 -0
- data/lib/straightedge/figures/line.rb +25 -0
- data/lib/straightedge/figures/mark.rb +23 -0
- data/lib/straightedge/figures/quadrilateral.rb +20 -0
- data/lib/straightedge/motor/adapter.rb +54 -0
- data/lib/straightedge/motor/engine.rb +16 -0
- data/lib/straightedge/origin.rb +3 -0
- data/lib/straightedge/presenter.rb +29 -0
- data/lib/straightedge/scene.rb +20 -0
- data/lib/straightedge/surface.rb +21 -0
- data/lib/straightedge/toolkit/compass.rb +19 -0
- data/lib/straightedge/toolkit/rose.rb +60 -0
- data/lib/straightedge/toolkit/ruler.rb +23 -0
- data/lib/straightedge/tools.rb +3 -0
- data/lib/straightedge/version.rb +1 -1
- data/spec/spec_helper.rb +4 -1
- data/spec/straightedge/adapter_spec.rb +14 -0
- data/spec/straightedge/director_spec.rb +10 -0
- data/spec/straightedge/extend/array_spec.rb +1 -6
- data/spec/straightedge/{figure_spec.rb → figures/figure_spec.rb} +0 -5
- data/spec/straightedge/figures/grid_spec.rb +31 -0
- data/spec/straightedge/figures/hexagon_spec.rb +7 -0
- data/spec/straightedge/motor/engine_spec.rb +11 -0
- data/spec/straightedge/scene_spec.rb +27 -0
- data/spec/straightedge/{compass_spec.rb → toolkit/compass_spec.rb} +0 -4
- data/spec/straightedge/{rose_spec.rb → toolkit/rose_spec.rb} +0 -5
- data/spec/straightedge/toolkit/ruler_spec.rb +14 -0
- data/spec/straightedge_spec.rb +35 -0
- metadata +54 -16
- data/.rvmrc +0 -1
- data/lib/straightedge/compass.rb +0 -17
- data/lib/straightedge/figure.rb +0 -28
- data/lib/straightedge/grid.rb +0 -34
- data/lib/straightedge/line.rb +0 -21
- data/lib/straightedge/mark.rb +0 -26
- data/lib/straightedge/rose.rb +0 -44
- data/lib/straightedge/ruler.rb +0 -21
- data/spec/straightedge/grid_spec.rb +0 -33
- data/spec/straightedge/ruler_spec.rb +0 -11
File without changes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Straightedge::Figures
|
2
|
+
class Hexagon < Figure
|
3
|
+
attr_accessor :scale
|
4
|
+
|
5
|
+
def initialize(location: Straightedge::ORIGIN, color: :white, scale: 1.0)
|
6
|
+
super(location: location, color: color)
|
7
|
+
@scale = scale
|
8
|
+
@marks = corners
|
9
|
+
end
|
10
|
+
|
11
|
+
# lots of magic here...
|
12
|
+
def left_triangle
|
13
|
+
corners[0..2]
|
14
|
+
end
|
15
|
+
|
16
|
+
def right_triangle
|
17
|
+
corners[3..5]
|
18
|
+
end
|
19
|
+
|
20
|
+
def center_quad
|
21
|
+
[corners[0], corners[2], corners[3], corners[5]]
|
22
|
+
end
|
23
|
+
|
24
|
+
def corners
|
25
|
+
Array.new(6) do |i|
|
26
|
+
angle = 2 * Math::PI / 6 * (i+2)
|
27
|
+
x_i = x + scale * Math.cos(angle)
|
28
|
+
y_i = y + scale * Math.sin(angle)
|
29
|
+
[x_i, y_i]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Straightedge
|
2
|
+
module Figures
|
3
|
+
class Line < Figure
|
4
|
+
def alpha
|
5
|
+
@marks[0]
|
6
|
+
end
|
7
|
+
|
8
|
+
def beta
|
9
|
+
@marks[1]
|
10
|
+
end
|
11
|
+
|
12
|
+
def dx
|
13
|
+
alpha.x - beta.x
|
14
|
+
end
|
15
|
+
|
16
|
+
def dy
|
17
|
+
alpha.y - beta.y
|
18
|
+
end
|
19
|
+
|
20
|
+
def length
|
21
|
+
Math.sqrt(dx*dx + dy*dy)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Straightedge
|
2
|
+
module Figures
|
3
|
+
#
|
4
|
+
# a mark is an optionally-colored position
|
5
|
+
#
|
6
|
+
class Mark
|
7
|
+
extend Forwardable
|
8
|
+
include Straightedge::Aspects::Colorable
|
9
|
+
|
10
|
+
attr_accessor :location
|
11
|
+
|
12
|
+
def initialize(*xy, color: :white)
|
13
|
+
@location = xy # [xy[0], xy[1]]
|
14
|
+
@color = color
|
15
|
+
end
|
16
|
+
|
17
|
+
def x; @location[0] end
|
18
|
+
def y; @location[1] end
|
19
|
+
|
20
|
+
def self.empty(*xy); new(*xy, color: :none) end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Straightedge
|
2
|
+
module Figures
|
3
|
+
class Quadrilateral < Figure
|
4
|
+
attr_reader :dimensions
|
5
|
+
def_delegator :dimensions, :x, :width
|
6
|
+
def_delegator :dimensions, :y, :height
|
7
|
+
|
8
|
+
def initialize(dimensions: [1,1], location: ORIGIN, color: :white)
|
9
|
+
super([], location: location, color: color)
|
10
|
+
@dimensions = dimensions
|
11
|
+
@marks = corners
|
12
|
+
end
|
13
|
+
|
14
|
+
def corners(w=width, h=height)
|
15
|
+
@corners ||= [[x,y],[x,y+h],[x+w,y+h],[x+w,y]]
|
16
|
+
#Rose.simple.project(origin).map { |xy| [xy.x*w, xy.y*h] }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Straightedge
|
2
|
+
class Adapter
|
3
|
+
include Straightedge::Figures
|
4
|
+
attr_accessor :agent
|
5
|
+
attr_reader :plane
|
6
|
+
|
7
|
+
def initialize(agent: Director.new, plane: nil)
|
8
|
+
@agent = agent
|
9
|
+
adapt(plane) if plane
|
10
|
+
end
|
11
|
+
|
12
|
+
def adapt(plane)
|
13
|
+
@plane = plane
|
14
|
+
@plane.adapter = self
|
15
|
+
@agent.prepare_stage([plane.width, plane.height])
|
16
|
+
end
|
17
|
+
|
18
|
+
def kickstart
|
19
|
+
@plane.display unless @plane.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def render
|
23
|
+
scene = @agent.current_scene.is_a?(Hash) ? Scene.new(agent.current_scene) : agent.current_scene
|
24
|
+
scene.render(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
# note the ordering is important, since e.g., grid < quad
|
28
|
+
def presenter_for(figure)
|
29
|
+
figures_and_presenters = Straightedge.config.presenter_classes
|
30
|
+
matched_class = figures_and_presenters.keys.detect { |k| figure.class <= k }
|
31
|
+
|
32
|
+
klass = if matched_class
|
33
|
+
figures_and_presenters[matched_class]
|
34
|
+
else
|
35
|
+
raise "no presenter class for #{figure}"
|
36
|
+
end
|
37
|
+
|
38
|
+
new_presenter = klass.new
|
39
|
+
new_presenter.on(@plane) unless @plane.nil?
|
40
|
+
new_presenter
|
41
|
+
end
|
42
|
+
|
43
|
+
def step
|
44
|
+
@agent.orchestrate
|
45
|
+
end
|
46
|
+
|
47
|
+
def click(x,y)
|
48
|
+
@agent.handle(:click, x, y)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
config.presenter_classes = {}
|
53
|
+
config.adapter_class = Adapter
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Straightedge
|
2
|
+
class Engine
|
3
|
+
attr_reader :adapter, :surface, :agent
|
4
|
+
def initialize(surface_geometry=Straightedge.config.geometry)
|
5
|
+
@agent = Straightedge.new_agent
|
6
|
+
@surface = Straightedge.new_surface(surface_geometry)
|
7
|
+
@adapter = Straightedge.new_adapter(agent: @agent, plane: @surface)
|
8
|
+
end
|
9
|
+
|
10
|
+
def boot
|
11
|
+
@adapter.kickstart
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
config.engine_class = Engine
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Straightedge
|
2
|
+
# TODO something with this
|
3
|
+
class Presenter
|
4
|
+
extend Forwardable
|
5
|
+
#def_delegators :location, :x, :y
|
6
|
+
|
7
|
+
def on(surface)
|
8
|
+
@surface = surface
|
9
|
+
self
|
10
|
+
end
|
11
|
+
|
12
|
+
#def at(p)
|
13
|
+
# @location = p
|
14
|
+
# self
|
15
|
+
#end
|
16
|
+
|
17
|
+
def display(figure)
|
18
|
+
raise 'implement in subclass'
|
19
|
+
end
|
20
|
+
|
21
|
+
#def location
|
22
|
+
# @location ||= [0,0]
|
23
|
+
#end
|
24
|
+
|
25
|
+
#def color(figure)
|
26
|
+
# @color ||= 0xEFEFEFEF
|
27
|
+
#end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Straightedge
|
2
|
+
# some boilerplate to bootstrap a rendering engine
|
3
|
+
class Scene
|
4
|
+
attr_reader :locations_and_figures
|
5
|
+
|
6
|
+
def initialize(locations_and_figures={})
|
7
|
+
@locations_and_figures = locations_and_figures
|
8
|
+
end
|
9
|
+
|
10
|
+
def render(adapter=nil)
|
11
|
+
return false unless adapter
|
12
|
+
@locations_and_figures.each do |location,figure|
|
13
|
+
figure = Figures::Label.new.says(figure) if figure.is_a?(String)
|
14
|
+
figure.location = location
|
15
|
+
presenter = adapter.presenter_for(figure)
|
16
|
+
presenter.display(figure)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Straightedge
|
2
|
+
module Surface
|
3
|
+
attr_accessor :adapter
|
4
|
+
attr_reader :width, :height
|
5
|
+
|
6
|
+
def display
|
7
|
+
warn 'implement in subclass'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class AbstractSurface
|
12
|
+
include Surface
|
13
|
+
|
14
|
+
def initialize(geometry, adapter: adapter)
|
15
|
+
@width, @height = *geometry
|
16
|
+
@adapter = adapter
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
config.surface_class = AbstractSurface
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Straightedge
|
2
|
+
module Toolkit
|
3
|
+
class Compass
|
4
|
+
extend Forwardable
|
5
|
+
attr_accessor :rose
|
6
|
+
def_delegator :rose, :project
|
7
|
+
|
8
|
+
def initialize(rose=Rose.extended)
|
9
|
+
@rose = rose
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def default
|
14
|
+
@default_compass ||= new
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Straightedge
|
2
|
+
module Toolkit
|
3
|
+
class Rose
|
4
|
+
attr_reader :directions
|
5
|
+
|
6
|
+
def initialize(directions:{})
|
7
|
+
@directions = directions
|
8
|
+
end
|
9
|
+
|
10
|
+
def project(point)
|
11
|
+
@directions.values.collect do |delta|
|
12
|
+
Ruler.translate(point, delta)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def simple
|
18
|
+
return @simple_rose unless @simple_rose.nil?
|
19
|
+
@simple_rose = new directions: {
|
20
|
+
:north => [0, -1],
|
21
|
+
:south => [0, 1],
|
22
|
+
:east => [1, 0],
|
23
|
+
:west => [-1, 0]
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
# for hex navigation (nb coords are in cube-space)
|
28
|
+
def hexagonal
|
29
|
+
return @hex_rose unless @hex_rose.nil?
|
30
|
+
@hex_rose = new directions: {
|
31
|
+
:north => [1, -1, 0],
|
32
|
+
:northeast => [0, -1, 1],
|
33
|
+
:northwest => [1, 0, -1],
|
34
|
+
:south => [-1, 1, 0],
|
35
|
+
:southeast => [-1, 0, 1],
|
36
|
+
:southwest => [0, 1, -1]
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def extended
|
41
|
+
return @extended_rose unless @extended_rose.nil?
|
42
|
+
simple_rose_axes = [[:east,:west],[:north, :south]]
|
43
|
+
extended_directions = permute(simple, simple_rose_axes)
|
44
|
+
all_directions = simple.directions.merge(extended_directions)
|
45
|
+
@extended_rose = new directions: all_directions
|
46
|
+
end
|
47
|
+
|
48
|
+
def permute(rose, axes)
|
49
|
+
combinations = axes.x.map do |x|
|
50
|
+
axes.y.map do |y|
|
51
|
+
["#{y}#{x}".to_sym, Ruler.translate(rose.directions[x], rose.directions[y])]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Hash[combinations.flatten(1)]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Straightedge
|
2
|
+
module Toolkit
|
3
|
+
class Ruler
|
4
|
+
attr_reader :unit
|
5
|
+
|
6
|
+
def initialize(unit: 1)
|
7
|
+
@unit = unit
|
8
|
+
end
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def default; @default ||= new end
|
12
|
+
|
13
|
+
def translate(xy, dxy)
|
14
|
+
xy.zip(dxy).map { |x,y| x+y }
|
15
|
+
end
|
16
|
+
|
17
|
+
def distance(alpha,beta)
|
18
|
+
Straightedge::Figures::Line.new([alpha,beta]).length
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/straightedge/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class GridPresenter; end
|
4
|
+
Straightedge.config.presenter_classes = { Grid => GridPresenter }
|
5
|
+
|
6
|
+
describe Adapter do
|
7
|
+
let(:director) { Director.new }
|
8
|
+
subject { Adapter.new(agent: director) }
|
9
|
+
|
10
|
+
it 'should find presenters' do
|
11
|
+
expect(subject.presenter_for(Grid.new)).to be_a(GridPresenter)
|
12
|
+
#expect(subject.presenter_for(Space.new)).to be_a(GridPresenter)
|
13
|
+
end
|
14
|
+
end
|
@@ -1,9 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'straightedge/mark'
|
3
|
-
require 'straightedge/figure'
|
4
|
-
require 'straightedge/compass'
|
5
|
-
require 'straightedge/rose'
|
6
|
-
require 'straightedge/extend/array'
|
7
2
|
require 'pry'
|
8
3
|
|
9
4
|
describe Array do
|
@@ -34,7 +29,7 @@ describe Array do
|
|
34
29
|
end
|
35
30
|
|
36
31
|
let(:expected_adjacent) do
|
37
|
-
[[
|
32
|
+
[[2, 2], [2, 3], [2, 1], [1, 1], [3, 1], [1, 3], [3, 3], [4, 2], [0, 2], [0, 1], [0, 3], [4, 1], [4, 3]]
|
38
33
|
end
|
39
34
|
it 'should have adjacent coordinates' do
|
40
35
|
expect(subject.adjacent).to eql(expected_adjacent)
|