straightedge 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +7 -0
  5. data/README.md +44 -2
  6. data/gemspec.yml +3 -0
  7. data/lib/straightedge.rb +33 -11
  8. data/lib/straightedge/aspects.rb +3 -0
  9. data/lib/straightedge/aspects/colorable.rb +8 -0
  10. data/lib/straightedge/aspects/figural.rb +12 -0
  11. data/lib/straightedge/aspects/positional.rb +10 -0
  12. data/lib/straightedge/colors.rb +72 -0
  13. data/lib/straightedge/config.rb +6 -0
  14. data/lib/straightedge/director.rb +39 -0
  15. data/lib/straightedge/extend/array.rb +2 -13
  16. data/lib/straightedge/figures.rb +8 -0
  17. data/lib/straightedge/{adapters.rb → figures/circle.rb} +0 -0
  18. data/lib/straightedge/figures/figure.rb +44 -0
  19. data/lib/straightedge/figures/grid.rb +65 -0
  20. data/lib/straightedge/figures/grid_cell.rb +0 -0
  21. data/lib/straightedge/figures/hexagon.rb +33 -0
  22. data/lib/straightedge/figures/label.rb +13 -0
  23. data/lib/straightedge/figures/line.rb +25 -0
  24. data/lib/straightedge/figures/mark.rb +23 -0
  25. data/lib/straightedge/figures/quadrilateral.rb +20 -0
  26. data/lib/straightedge/motor/adapter.rb +54 -0
  27. data/lib/straightedge/motor/engine.rb +16 -0
  28. data/lib/straightedge/origin.rb +3 -0
  29. data/lib/straightedge/presenter.rb +29 -0
  30. data/lib/straightedge/scene.rb +20 -0
  31. data/lib/straightedge/surface.rb +21 -0
  32. data/lib/straightedge/toolkit/compass.rb +19 -0
  33. data/lib/straightedge/toolkit/rose.rb +60 -0
  34. data/lib/straightedge/toolkit/ruler.rb +23 -0
  35. data/lib/straightedge/tools.rb +3 -0
  36. data/lib/straightedge/version.rb +1 -1
  37. data/spec/spec_helper.rb +4 -1
  38. data/spec/straightedge/adapter_spec.rb +14 -0
  39. data/spec/straightedge/director_spec.rb +10 -0
  40. data/spec/straightedge/extend/array_spec.rb +1 -6
  41. data/spec/straightedge/{figure_spec.rb → figures/figure_spec.rb} +0 -5
  42. data/spec/straightedge/figures/grid_spec.rb +31 -0
  43. data/spec/straightedge/figures/hexagon_spec.rb +7 -0
  44. data/spec/straightedge/motor/engine_spec.rb +11 -0
  45. data/spec/straightedge/scene_spec.rb +27 -0
  46. data/spec/straightedge/{compass_spec.rb → toolkit/compass_spec.rb} +0 -4
  47. data/spec/straightedge/{rose_spec.rb → toolkit/rose_spec.rb} +0 -5
  48. data/spec/straightedge/toolkit/ruler_spec.rb +14 -0
  49. data/spec/straightedge_spec.rb +35 -0
  50. metadata +54 -16
  51. data/.rvmrc +0 -1
  52. data/lib/straightedge/compass.rb +0 -17
  53. data/lib/straightedge/figure.rb +0 -28
  54. data/lib/straightedge/grid.rb +0 -34
  55. data/lib/straightedge/line.rb +0 -21
  56. data/lib/straightedge/mark.rb +0 -26
  57. data/lib/straightedge/rose.rb +0 -44
  58. data/lib/straightedge/ruler.rb +0 -21
  59. data/spec/straightedge/grid_spec.rb +0 -33
  60. 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,13 @@
1
+ module Straightedge
2
+ module Figures
3
+ # technically a label isn't even a figure, just a mark with an associated string
4
+ class Label < Mark
5
+ attr_reader :text
6
+
7
+ def says(text)
8
+ @text = text
9
+ self
10
+ end
11
+ end
12
+ end
13
+ 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,3 @@
1
+ module Straightedge
2
+ ORIGIN = [0, 0]
3
+ 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
@@ -0,0 +1,3 @@
1
+ require 'straightedge/toolkit/compass'
2
+ require 'straightedge/toolkit/rose'
3
+ require 'straightedge/toolkit/ruler'
@@ -1,4 +1,4 @@
1
1
  module Straightedge
2
2
  # straightedge version
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require 'rspec'
2
+ require 'rspec/its'
2
3
  require 'pry'
3
- require 'straightedge/version'
4
+ require 'straightedge'
4
5
 
5
6
  include Straightedge
7
+ include Straightedge::Figures
8
+ include Straightedge::Toolkit
@@ -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
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ describe Director do
3
+ subject { Director.new }
4
+ let(:adapter) { Adapter.new(agent: subject) }
5
+
6
+ it 'should respond to adapter events' do
7
+ expect(subject).to receive(:handle).with(:click, 1,2)
8
+ adapter.click(1,2)
9
+ end
10
+ 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
- [[1, 1], [1, 3], [2, 2], [0, 2], [2, 1], [2, 3], [0, 1], [0, 3], [3, 1], [3, 3], [4, 2], [4, 1], [4, 3]]
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)