rpiet 0.1 → 0.2

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 (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +12 -0
  4. data/bin/color_wheel +84 -0
  5. data/bin/image_gen +39 -0
  6. data/bin/rpiet +68 -11
  7. data/images/counter.txt +7 -0
  8. data/lib/rpiet/asg/graph_interpreter.rb +39 -0
  9. data/lib/rpiet/asg/parser.rb +156 -0
  10. data/lib/rpiet/asg/visitor.rb +66 -0
  11. data/lib/rpiet/asg.rb +336 -0
  12. data/lib/rpiet/codel_chooser.rb +32 -4
  13. data/lib/rpiet/color.rb +70 -25
  14. data/lib/rpiet/cycle.rb +18 -7
  15. data/lib/rpiet/debugger/debugger.rb +298 -0
  16. data/lib/rpiet/debugger/stylesheet.css +88 -0
  17. data/lib/rpiet/direction_pointer.rb +49 -18
  18. data/lib/rpiet/event_handler.rb +62 -7
  19. data/lib/rpiet/group.rb +25 -8
  20. data/lib/rpiet/image/ascii_image.rb +8 -20
  21. data/lib/rpiet/image/image.rb +8 -3
  22. data/lib/rpiet/image/url_image.rb +28 -14
  23. data/lib/rpiet/interpreter.rb +72 -72
  24. data/lib/rpiet/ir/assembler.rb +87 -0
  25. data/lib/rpiet/ir/builder.rb +255 -0
  26. data/lib/rpiet/ir/cfg.rb +494 -0
  27. data/lib/rpiet/ir/instructions.rb +536 -0
  28. data/lib/rpiet/ir/ir_cfg_interpreter.rb +23 -0
  29. data/lib/rpiet/ir/ir_interpreter.rb +101 -0
  30. data/lib/rpiet/ir/ir_native_interpreter.rb +77 -0
  31. data/lib/rpiet/ir/jruby_backend.rb +279 -0
  32. data/lib/rpiet/ir/operands.rb +28 -0
  33. data/lib/rpiet/ir/passes/data_flow_problem.rb +32 -0
  34. data/lib/rpiet/ir/passes/flow_graph_node.rb +76 -0
  35. data/lib/rpiet/ir/passes/peephole.rb +214 -0
  36. data/lib/rpiet/ir/passes/push_pop_elimination_pass.rb +112 -0
  37. data/lib/rpiet/live_machine_state.rb +15 -0
  38. data/lib/rpiet/machine.rb +62 -32
  39. data/lib/rpiet/source.rb +83 -0
  40. data/lib/rpiet/version.rb +1 -1
  41. data/lib/rpiet.rb +2 -2
  42. data/rpiet.gemspec +19 -0
  43. data/spec/asg/visitor_spec.rb +41 -0
  44. data/spec/cycle_spec.rb +34 -34
  45. data/spec/direction_pointer_spec.rb +33 -6
  46. data/spec/group_spec.rb +73 -48
  47. data/spec/interpreter_spec.rb +161 -12
  48. data/spec/ir/assembler_spec.rb +122 -0
  49. data/spec/ir/builder_spec.rb +20 -0
  50. data/spec/ir/cfg_spec.rb +151 -0
  51. data/spec/ir/ir_interpreter_spec.rb +102 -0
  52. data/spec/ir/passes/push_pop_elimination_pass_spec.rb +34 -0
  53. data/spec/machine_spec.rb +5 -3
  54. data/spec/source_spec.rb +69 -0
  55. data/spec/spec_helper.rb +78 -0
  56. metadata +54 -16
  57. data/images/nfib.png +0 -0
@@ -0,0 +1,298 @@
1
+ require 'jrubyfx'
2
+ require 'thread'
3
+
4
+ # FIXME : JRubyFX is not implementing add correctly.
5
+ class Java::JavafxSceneControl::ScrollPane
6
+ def add(child)
7
+ set_content(child)
8
+ end
9
+ end
10
+
11
+ module RPiet
12
+
13
+ class Debugger < JRubyFX::Application
14
+ include JRubyFX
15
+
16
+ attr_reader :stage
17
+
18
+ DEFAULT_DELAY = 0.25 # seconds
19
+ SIZE = 30
20
+ NORMAL = Java::javafx.scene.paint.Color.web("0x222222")
21
+ CANDIDATE = Java::javafx.scene.paint.Color::YELLOW
22
+ BREAKPOINT = Java::javafx.scene.paint.Color::RED
23
+ CURRENT = Java::javafx.scene.paint.Color::CADETBLUE
24
+ WHITE = Java::javafx.scene.paint.Color::WHITE
25
+
26
+ ARROW = [2, 9, 11, 9, 10, 4, 18, 10, 10, 16, 11, 11, 2, 11].to_java(:double)
27
+
28
+ def self.instance
29
+ @@instance
30
+ end
31
+
32
+ def break_point?(x,y)
33
+ @break_points["#{x}x#{y}"]
34
+ end
35
+
36
+ def update_directions(start_x, start_y, end_x, end_y)
37
+ stage["#connector"].tap do |connector|
38
+ connector.start_x = SIZE/2 + codel2pixels(start_x)
39
+ connector.start_y = SIZE/2 + codel2pixels(start_y)
40
+ connector.end_x = SIZE/2 + codel2pixels(end_x)
41
+ connector.end_y = SIZE/2 + codel2pixels(end_y)
42
+ end
43
+ end
44
+
45
+ def codel2pixels(codel_offset)
46
+ (codel_offset + 1) * SIZE
47
+ end
48
+
49
+ def begin_session
50
+ update_directions(-1, 0, 0, 0)
51
+ end
52
+
53
+ def highlight_candidate(runtime, edge_x, edge_y, next_x, next_y, valid)
54
+ update_directions(edge_x, edge_y, next_x, next_y)
55
+ # Replace with black edge in debugger later
56
+ if next_x < 0 || next_y < 0 || next_x >= runtime.source.cols || next_y >= runtime.source.rows
57
+ puts "OUT OF BOUNDS #{next_x} #{next_y} #{runtime.source.rows} #{runtime.source.cols}"
58
+ return
59
+ end
60
+ run_later do
61
+ stage["\##{next_x}x#{next_y}"].stroke = CANDIDATE
62
+ if @lastc_x
63
+ color = break_point?(@lastc_x, @lastc_y) ? BREAKPOINT : NORMAL
64
+ if color == NORMAL && stage["\##{@lastc_x}x#{@lastc_y}"].stroke != CURRENT
65
+ stage["\##{@lastc_x}x#{@lastc_y}"].stroke = color
66
+ end
67
+ end
68
+ @lastc_x, @lastc_y = next_x, next_y
69
+ end
70
+ end
71
+
72
+ def highlight(runtime, x, y)
73
+ run_later do
74
+ stage["\##{x}x#{y}"].stroke = CURRENT
75
+ if @last_x
76
+ color = break_point?(@last_x, @last_y) ? BREAKPOINT : NORMAL
77
+ stage["\##{@last_x}x#{@last_y}"].stroke = color
78
+ end
79
+ @last_x, @last_y = x, y
80
+
81
+ #@stage["#connector"].visible = false
82
+ stage["#dp-arrow"].rotate = @rpiet.pvm.dp.degrees
83
+ stage["#cc-arrow"].rotate = @rpiet.pvm.cc.degrees(@rpiet.pvm.dp)
84
+ stage["#cc-text"].text = @rpiet.pvm.cc.to_s
85
+
86
+ percent_y = y.to_f / (@rpiet.source.rows + 2)
87
+ percent_x = x.to_f / (@rpiet.source.cols + 2)
88
+ virtual_w = (@rpiet.source.cols + 2) * SIZE
89
+ virtual_h = (@rpiet.source.rows + 2) * SIZE
90
+ sb = stage['#scrollbar']
91
+ real_x, real_y = x * 43, y * 43 # I lay out 30x30 but they end up 43x43 on screen?
92
+ real_w, real_h = sb.width, sb.height
93
+ s_x, s_y = sb.hvalue * virtual_w, sb.vvalue * virtual_h
94
+
95
+ # FIXME: Add x,y offset guides on out of bound blocks so scrolling is less confusing
96
+ # FIXME: Clean this up and use a clamp so we do not exceed scroll bounds
97
+ a_x = real_x - s_x
98
+ if a_x > real_w
99
+ sb.hvalue += 0.1
100
+ elsif a_x < 0
101
+ sb.hvalue -= 0.1
102
+ end
103
+
104
+ a_y = real_y - s_y
105
+ if a_y > real_h
106
+ sb.vvalue += 0.1
107
+ elsif a_y < 0
108
+ sb.vvalue -= 0.1
109
+ end
110
+
111
+
112
+ # puts "VirtW: #{virtual_w}, REAL_W: #{real_w}"
113
+ # puts "S_X: #{(sb.hvalue * virtual_w).to_i} #{x * 43}"
114
+ # puts "V: #{percent_y} #{sb.vmax} #{sb.vvalue} H: #{percent_x} #{sb.hmax} #{sb.hvalue}"
115
+ runtime.pause if break_point?(x, y)
116
+ end
117
+ end
118
+
119
+ def operation(runtime, oper)
120
+ run_later do
121
+ puts "operation"
122
+ stage['#oper'].text = "oper: " + oper.to_s
123
+ stage['#stack'].text = "stack: " + runtime.pvm.stack.inspect
124
+ stage['#bv'].text = "value: " + runtime.pvm.block_value.inspect
125
+ stage['#state-values'].visible = true
126
+ end
127
+ end
128
+
129
+ # JavaFX has some caching so we cheat the cache by using file: uri and varying the uri by adding a time param.
130
+ def reload_stylesheet(scene)
131
+ run_later do
132
+ scene.stylesheets.clear
133
+ scene.stylesheets.add(File.join('file:' + File.dirname(__FILE__), (@odd_load_css ? '/./' : '') + "stylesheet.css"))
134
+ @odd_load_css = !@odd_load_css
135
+ end
136
+ end
137
+
138
+ def watch_stylesheet(scene)
139
+ file = File.join(File.dirname(__FILE__), "stylesheet.css")
140
+ last_time = File.mtime(file)
141
+ Thread.new do
142
+ loop do
143
+ mtime = File.mtime(file)
144
+
145
+ if mtime != last_time
146
+ reload_stylesheet(scene)
147
+ last_time = mtime
148
+ else
149
+ sleep 1
150
+ end
151
+ end
152
+ end.run
153
+ end
154
+
155
+ def start(stage)
156
+ @rpiet = $rpiet # how does jrubyfx pass params before start is called?
157
+ @break_points = break_points = {}
158
+ @stage = stage
159
+ debugger = self
160
+ @rpiet.delay = DEFAULT_DELAY
161
+
162
+ # FIXME: Move into convenience module near top of JRubyFX hier. Maybe make a feature for these
163
+ ::Kernel.instance_eval {
164
+ define_method(:codel) { |i=1| SIZE * i}
165
+ define_method(:half_codel) { SIZE/2 }
166
+ }
167
+ rows, cols, pixels = @rpiet.source.rows, @rpiet.source.cols, @rpiet.source.pixels
168
+ rpiet = @rpiet
169
+ stroke_width = SIZE / 10
170
+ with(stage, title: "RPiet", width: 800, height: 600) do
171
+ layout_scene do
172
+ vbox(id: 'main') do
173
+ border_pane do
174
+ top(menu_bar! do
175
+ menu("File") do
176
+ menu_item("Quit") do
177
+ set_on_action do |event|
178
+ rpiet.abort
179
+ Platform.exit
180
+ end
181
+ end
182
+ end
183
+ menu("View") do
184
+ menu_item("Reload Stylesheet") { set_on_action { |_| debugger.reload_stylesheet(stage.scene) } }
185
+ menu_item("Pause (0.025s)") { set_on_action { |_| rpiet.delay = 0.025 } }
186
+ menu_item("Pause (0.1s)") { set_on_action { |_| rpiet.delay = 0.1 } }
187
+ menu_item("Pause (#{DEFAULT_DELAY}s)") { set_on_action { |_| rpiet.delay = DEFAULT_DELAY } }
188
+ end
189
+ end)
190
+ left(hbox(id: 'state') do
191
+ label("DP", id: 'dp-label')
192
+ polygon(ARROW, id: 'dp-arrow')
193
+ label("CC:", id: 'cc-label')
194
+ polygon(ARROW, id: 'cc-arrow')
195
+ label(rpiet.pvm.cc.to_s, id: 'cc-text')
196
+ hbox(id: 'state-values') do
197
+ label("oper:", id: 'oper')
198
+ label("value: ", id: 'bv')
199
+ label("stack:", id: 'stack')
200
+ end
201
+ end)
202
+ right(hbox do
203
+ get_style_class.add "controls"
204
+ button("restart") do
205
+ get_style_class.add "control"
206
+ set_on_action { |_| rpiet.restart }
207
+ end
208
+ button("pause") do
209
+ get_style_class.add "control"
210
+ set_on_action { |_| rpiet.pause }
211
+ end
212
+ button("resume") do
213
+ get_style_class.add "control"
214
+ set_on_action { |_| rpiet.resume }
215
+ end
216
+ button("step") do
217
+ get_style_class.add "control"
218
+ set_on_action { |_| rpiet.advance }
219
+ end
220
+ end)
221
+ end
222
+ scroll_pane(id: 'scrollbar') do |sp|
223
+ sp.set_content(group() do
224
+ Java::javafx.scene.layout.VBox.setVgrow(sp, Java::javafx.scene.layout.Priority::ALWAYS)
225
+
226
+ # Horizontal top and bottom border
227
+ (rpiet.source.cols + 2).times do |i|
228
+ rectangle(codel(i), 0, codel-1, codel-1, stroke_type: :inside, stroke: NORMAL) do
229
+ get_style_class.add "out-of-bounds"
230
+ end
231
+ text(codel(i) + half_codel, half_codel, (i-1).to_s) if i != 0 && i != cols + 1
232
+
233
+ rectangle(codel(i), codel(rpiet.source.rows + 1), codel-1, codel-1,
234
+ stroke_type: :inside, stroke: NORMAL) do
235
+ get_style_class.add "out-of-bounds"
236
+ end
237
+ text(codel(i) + half_codel, codel(rows + 1) + half_codel, (i-1).to_s) if i != 0 && i != cols + 1
238
+
239
+ end
240
+
241
+ # Left and right vertical border
242
+ group do
243
+ rpiet.source.rows.times do |j|
244
+ rectangle(0, codel(j + 1), codel-1, codel-1, stroke_type: :inside, stroke: NORMAL) do
245
+ get_style_class.add "out-of-bounds"
246
+ end
247
+ text(half_codel, codel(j + 1) + half_codel, j.to_s)
248
+
249
+ rectangle(codel(cols + 1), codel(j + 1), codel-1, codel-1, stroke_type: :inside, stroke: NORMAL) do
250
+ get_style_class.add "out-of-bounds"
251
+ end
252
+ text(codel(cols + 1) + half_codel, codel(j + 1) + half_codel, j.to_s)
253
+ end
254
+ end
255
+
256
+ # Main codels
257
+ pixels.each_with_index do |row, i|
258
+ row.each_with_index do |piet_pixel, j|
259
+ color = Java::javafx.scene.paint.Color.web(piet_pixel.rgb)
260
+ ident = "#{i}x#{j}"
261
+ rectangle(codel(i+1), codel(j+1), codel-1, codel-1, fill: color,
262
+ stroke_type: :inside, stroke_width: stroke_width,
263
+ stroke: NORMAL, stroke_line_join: :round, id: ident) do
264
+ get_style_class.add "codel"
265
+ set_on_mouse_clicked do |event|
266
+ new_color = if event.source.stroke == BREAKPOINT
267
+ break_points[ident] = nil
268
+ NORMAL
269
+ else
270
+ break_points[ident] = event.source
271
+ BREAKPOINT
272
+ end
273
+ event.source.stroke = new_color
274
+ end
275
+ end
276
+ end
277
+ end
278
+ # FIXME: stroke_width must be derived but I feel I need to add scrolling and a minimum
279
+ # codel display SIZE before I can do this.
280
+ line(start_x: half_codel, start_y: codel + half_codel,
281
+ end_x: codel + half_codel, end_y: codel + half_codel, stroke_width: 10, id: 'connector')
282
+ end)
283
+ end
284
+ end
285
+ end
286
+ end.show
287
+
288
+ stage.set_on_close_request {
289
+ rpiet.abort
290
+ Platform.exit
291
+ }
292
+ $event_handler.debugger_started self
293
+ begin_session
294
+ reload_stylesheet(stage.scene)
295
+ watch_stylesheet(stage.scene)
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,88 @@
1
+ #bv {
2
+ -fx-text-fill: #ffffff;
3
+ -fx-padding: 3;
4
+ }
5
+
6
+ #cc-arrow {
7
+ -fx-fill: #ffffff;
8
+ -fx-padding: 3;
9
+ -fx-stroke_width: 6;
10
+ }
11
+
12
+ #cc-label {
13
+ -fx-text-fill: #ffffff;
14
+ -fx-padding: 3;
15
+ -fx-font-size: 28;
16
+ }
17
+
18
+ #cc-text {
19
+ -fx-text-fill: #ffffff;
20
+ -fx-font-size: 28;
21
+ }
22
+
23
+ .codel {
24
+ -fx-arc-width: 1;
25
+ -fx-arc-width: 1;
26
+ -fx-stroke-width: 2;
27
+ -fx-background-color: #444455;
28
+ }
29
+
30
+ #connector {
31
+ -fx-fill: #999999;
32
+ -fx-stroke-width: 4;
33
+ }
34
+
35
+ .controls {
36
+ -fx-padding: 10;
37
+ -fx-text-fill: #000000;
38
+ }
39
+
40
+ .control {
41
+ -fx-text-fill: #000000;
42
+ }
43
+
44
+ #dp {
45
+ -fx-spacing: 20;
46
+ }
47
+
48
+ #dp-arrow {
49
+ -fx-fill: #ffffff;
50
+ }
51
+
52
+ #dp-label {
53
+ -fx-text-fill: #ffffff;
54
+ -fx-font-size: 28;
55
+ }
56
+
57
+ #main {
58
+ -fx-background-color: #444455;
59
+ }
60
+
61
+ #oper {
62
+ -fx-text-fill: #ffffff;
63
+ -fx-padding: 3;
64
+ }
65
+
66
+ .out-of-bounds {
67
+ -fx-arc-width: 1;
68
+ -fx-arc-width: 1;
69
+ -fx-stroke-width: 0;
70
+ -fx-fill: #999999;
71
+ }
72
+
73
+ #stack {
74
+ -fx-text-fill: #ffffff;
75
+ -fx-padding: 3;
76
+ }
77
+
78
+ #state {
79
+ -fx-padding: 40;
80
+ }
81
+
82
+ #state-values {
83
+ }
84
+
85
+ #value {
86
+ -fx-text-fill: #ffffff;
87
+ -fx-padding: 3;
88
+ }
@@ -1,39 +1,70 @@
1
- require 'rpiet/cycle'
2
- require 'rpiet/codel_chooser'
1
+ require_relative 'cycle'
2
+ require_relative 'codel_chooser'
3
3
 
4
4
  module RPiet
5
5
  extend RPiet::CycleMethod
6
6
  cycle :Direction, :RIGHT, :DOWN, :LEFT, :UP
7
7
 
8
- class << Direction::RIGHT; def deltas; [1, 0]; end; end
9
- class << Direction::DOWN; def deltas; [0, 1]; end; end
10
- class << Direction::LEFT; def deltas; [-1, 0]; end; end
11
- class << Direction::UP; def deltas; [0, -1]; end; end
8
+ module DirectionExtras
9
+ def next_point(x, y)
10
+ dx, dy = deltas
11
+ [x + dx, y + dy]
12
+ end
13
+ end
14
+
15
+ class << Direction::RIGHT
16
+ include DirectionExtras
17
+ def deltas = [1, 0]
18
+ end
19
+
20
+ class << Direction::DOWN
21
+ include DirectionExtras
22
+ def deltas = [0, 1]
23
+ end
24
+
25
+ class << Direction::LEFT
26
+ include DirectionExtras
27
+ def deltas = [-1, 0]
28
+ end
29
+
30
+ class << Direction::UP
31
+ include DirectionExtras
32
+ def deltas = [0, -1]
33
+ end
12
34
 
13
35
  class DirectionPointer
14
- attr_reader :direction
36
+ attr_accessor :direction
37
+
38
+ def initialize(value=nil)
39
+ @direction = value ? RPiet::Direction::RIGHT.abs(value) : RPiet::Direction::RIGHT
40
+ end
15
41
 
16
- def initialize
17
- @direction = RPiet::Direction::RIGHT
42
+ def ==(other)
43
+ @direction == other.direction
18
44
  end
19
45
 
20
46
  def rotate!(amount = 1)
21
47
  @direction = @direction.incr amount
48
+ self
22
49
  end
23
50
 
24
- def next_possible(x, y)
25
- dx, dy = @direction.deltas
26
- [x + dx, y + dy]
51
+ def degrees = @direction.value * 90
52
+
53
+ def from_ordinal!(ordinal)
54
+ @direction = @direction.abs(ordinal)
55
+ self
27
56
  end
28
57
 
58
+ def as_constant = %w[RIGHT DOWN LEFT UP][ordinal]
59
+
60
+ def next_possible(x, y) = @direction.next_point(x, y)
61
+
62
+ def ordinal = @direction.value
63
+
29
64
  ASCII_ARROWS = ['>', 'v', '<', '^']
30
- def ascii
31
- ASCII_ARROWS[@direction.value]
32
- end
65
+ def ascii = ASCII_ARROWS[@direction.value]
33
66
 
34
- def inspect
35
- @direction.inspect
36
- end
67
+ def inspect = ordinal.to_s
37
68
  alias :to_s :inspect
38
69
  end
39
70
  end
@@ -7,7 +7,10 @@ module RPiet
7
7
  def initialized(runtime)
8
8
  end
9
9
 
10
- def step_begin(runtime)
10
+ def next_possible(runtime, edge_x, edge_y, next_x, next_y, valid)
11
+ end
12
+
13
+ def step_begin(runtime, ex, ey)
11
14
  end
12
15
 
13
16
  def trying_again(runtime, ex, ey)
@@ -19,7 +22,10 @@ module RPiet
19
22
  def execution_completed(runtime)
20
23
  end
21
24
 
22
- def operation(runtime, operation)
25
+ def operation(runtime, step, operation)
26
+ end
27
+
28
+ def instruction(runtime, instruction)
23
29
  end
24
30
  end
25
31
 
@@ -33,10 +39,11 @@ module RPiet
33
39
 
34
40
  def initialized(runtime)
35
41
  dmesg "codel_size: #{runtime.source.codel_size}"
42
+ dmesg "size: #{runtime.source.cols}x#{runtime.source.rows}"
36
43
  end
37
44
 
38
- def step_begin(runtime)
39
- dmesg "step \##{runtime.step} -- #{runtime.pvm}"
45
+ def step_begin(runtime, ex, ey)
46
+ dmesg "step \##{runtime.step} at #{ex} #{ey} -- #{runtime.pvm}"
40
47
  end
41
48
 
42
49
  def trying_again(runtime, ex, ey)
@@ -51,16 +58,64 @@ module RPiet
51
58
  dmesg "Execution trapped, program terminates"
52
59
  end
53
60
 
54
- def operation(runtime, operation)
55
- dmesg "exec: #{operation} -- #{runtime.pvm}"
61
+ def instruction(runtime, instruction)
62
+ dmesg " instr: #{instruction}"
63
+ end
64
+
65
+ def operation(runtime, step, operation)
66
+ dmesg "exec: step: \##{step} oper: #{operation}, #{runtime}"
56
67
  end
57
68
  end
58
69
 
59
70
  class ComplexAsciiOutput < SimpleAsciiOutput
60
- def step_begin(runtime)
71
+ def step_begin(runtime, ex, ey)
61
72
  super
62
73
  dmesg runtime.source.ascii(runtime.groups[runtime.x][runtime.y])
63
74
  end
64
75
  end
76
+
77
+ class Graphical < SimpleAsciiOutput
78
+ def initialized(runtime)
79
+ unless $event_handler
80
+ require 'rpiet/debugger/debugger'
81
+ $rpiet = runtime
82
+ $event_handler = self
83
+ Thread.new { RPiet::Debugger.launch }.run
84
+ else
85
+ @debugger.begin_session
86
+ end
87
+ runtime.pause
88
+ end
89
+
90
+ def debugger_started(debugger)
91
+ @debugger = debugger
92
+ end
93
+
94
+ def step_begin(runtime, ex, ey)
95
+ @debugger.highlight(runtime, ex, ey)
96
+ if @debugger.break_point?(ex, ey)
97
+ puts "Break point at #{ex}, #{ey}"
98
+ end
99
+ end
100
+ alias :trying_again :step_begin
101
+
102
+ # edge of current group to potential entry point of next group (valid is if next is a valid group).
103
+ def next_possible(runtime, edge_x, edge_y, next_x, next_y, valid)
104
+ @debugger.highlight_candidate(runtime, edge_x, edge_y, next_x, next_y, valid)
105
+ end
106
+
107
+ def operation(runtime, step, operation)
108
+ # FIXME: display step in debugger
109
+ @debugger.operation(runtime, operation)
110
+ end
111
+
112
+ def seen_white(runtime)
113
+ puts "SEEN WHITE"
114
+ end
115
+
116
+ def trying_again(runtime, ex, ey)
117
+ @debugger.highlight(runtime, ex, ey)
118
+ end
119
+ end
65
120
  end
66
121
  end
data/lib/rpiet/group.rb CHANGED
@@ -1,16 +1,22 @@
1
- require 'rpiet/direction_pointer'
2
- require 'rpiet/codel_chooser'
1
+ require 'set'
2
+ require_relative 'direction_pointer'
3
+ require_relative 'codel_chooser'
3
4
 
4
5
  module RPiet
5
6
  class Group
6
7
  include RPiet::Direction
7
- attr_reader :rgb, :points
8
+ attr_reader :color, :points
8
9
 
9
- def initialize(rgb, point)
10
- @rgb, @points = rgb, []
10
+ # represents significant corners in a group based on the dp and cc.
11
+ # First letter is the dp: {r-ight, l-eft, d-own, u-p}.
12
+ # The second letter is the codel chooser: {l-eft, r-ight}.
13
+ attr_reader :rl, :rr, :lr, :ll, :ul, :ur, :dr, :dl
14
+
15
+ def initialize(color, *points)
16
+ @color, @points = color, []
11
17
  @max = { RIGHT => [], LEFT => [], UP => [], DOWN => [] }
12
18
 
13
- self << point
19
+ points.each { |point| self << point}
14
20
  end
15
21
 
16
22
  def point_for(pvm)
@@ -35,11 +41,22 @@ module RPiet
35
41
  @points << point
36
42
  end
37
43
 
44
+ def edges
45
+ edges = Set.new
46
+ @points.each do |x, y|
47
+ edges.add [x, y, :up] unless @points.include?(UP.next_point(x, y))
48
+ edges.add [x, y, :down] unless @points.include? DOWN.next_point(x, y)
49
+ edges.add [x, y, :left] unless @points.include?(LEFT.next_point(x, y))
50
+ edges.add [x, y, :right] unless @points.include? RIGHT.next_point(x, y)
51
+ end
52
+ edges
53
+ end
54
+
38
55
  def include?(point)
39
56
  @points.include? point
40
57
  end
41
58
 
42
- def finish
59
+ def calculate_corners
43
60
  @rl, @rr = ends(@max[RIGHT].sort { |a, b| a[1] <=> b[1] })
44
61
  @lr, @ll = ends(@max[LEFT].sort { |a, b| a[1] <=> b[1] })
45
62
  @ul, @ur = ends(@max[UP].sort { |a, b| a[0] <=> b[0] })
@@ -99,7 +116,7 @@ module RPiet
99
116
  end
100
117
 
101
118
  def inspect
102
- "Group #{rgb}: Size: #{size} Points: #{@points.inspect}\n" +
119
+ "Group #{color}: Size: #{size} Points: #{@points.inspect}\n" +
103
120
  "rr #@rr rl #@rl lr #@lr ll #@ll ur #@ur ul #@ul dr #@dr dl #@dl"
104
121
  end
105
122
  alias :to_s :inspect
@@ -4,25 +4,15 @@ module RPiet
4
4
  module Image
5
5
  class AsciiImage < RPiet::Image::Image
6
6
  def initialize(string, codel_size=1)
7
- @codel_size = codel_size
8
- lines = string.split("\n")
9
- @data = []
10
- lines.each do |line|
11
- @data << line.split(/\s+/).map { |e| str_to_rgb(e) }
7
+ super codel_size
8
+ @data = string.each_line(chomp: true).map do |line|
9
+ line.split(/\s+/).map { |e| str_to_rgb(e) }
12
10
  end
13
11
  end
14
12
 
15
- def raw_pixel(x, y)
16
- @data[x][y]
17
- end
18
-
19
- def raw_height
20
- @data.length
21
- end
22
-
23
- def raw_width
24
- @data[0].length
25
- end
13
+ def raw_pixel(x, y) = @data[y][x]
14
+ def raw_height = @data.length
15
+ def raw_width = @data[0].length
26
16
 
27
17
  STR2RGB = {
28
18
  'lr' => [0xff, 0xc0, 0xc0],
@@ -33,7 +23,7 @@ module RPiet
33
23
  'lm' => [0xff, 0xc0, 0xff],
34
24
  'nr' => [0xff, 0x00, 0x00],
35
25
  'ny' => [0xff, 0xff, 0x00],
36
- 'ng' => [0xc0, 0xff, 0x00],
26
+ 'ng' => [0x00, 0xff, 0x00],
37
27
  'nc' => [0x00, 0xff, 0xff],
38
28
  'nb' => [0x00, 0x00, 0xff],
39
29
  'nm' => [0xff, 0x00, 0xff],
@@ -47,9 +37,7 @@ module RPiet
47
37
  '++' => [0x00, 0x00, 0x00]
48
38
  }
49
39
 
50
- def str_to_rgb(str)
51
- STR2RGB[str]
52
- end
40
+ def str_to_rgb(str) = STR2RGB[str]
53
41
  end
54
42
  end
55
43
  end