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