amaze 0.2.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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +110 -0
  8. data/Rakefile +6 -0
  9. data/amaze.gemspec +30 -0
  10. data/bin/console +15 -0
  11. data/bin/setup +8 -0
  12. data/exe/amaze +5 -0
  13. data/lib/amaze.rb +17 -0
  14. data/lib/amaze/algorithm.rb +44 -0
  15. data/lib/amaze/algorithm/aldous_border.rb +36 -0
  16. data/lib/amaze/algorithm/binary_tree.rb +20 -0
  17. data/lib/amaze/algorithm/growing_tree.rb +52 -0
  18. data/lib/amaze/algorithm/hunt_and_kill.rb +53 -0
  19. data/lib/amaze/algorithm/recursive_backtracker.rb +77 -0
  20. data/lib/amaze/algorithm/sidewinder.rb +42 -0
  21. data/lib/amaze/algorithm/wilson.rb +54 -0
  22. data/lib/amaze/cell.rb +63 -0
  23. data/lib/amaze/cell/hex.rb +10 -0
  24. data/lib/amaze/cell/octo.rb +10 -0
  25. data/lib/amaze/cell/polar.rb +16 -0
  26. data/lib/amaze/cell/square.rb +10 -0
  27. data/lib/amaze/distances.rb +53 -0
  28. data/lib/amaze/factory.rb +153 -0
  29. data/lib/amaze/formatter.rb +5 -0
  30. data/lib/amaze/formatter/ascii.rb +91 -0
  31. data/lib/amaze/formatter/ascii/delta.rb +180 -0
  32. data/lib/amaze/formatter/ascii/ortho.rb +105 -0
  33. data/lib/amaze/formatter/ascii/polar.rb +199 -0
  34. data/lib/amaze/formatter/ascii/sigma.rb +213 -0
  35. data/lib/amaze/formatter/ascii/upsilon.rb +281 -0
  36. data/lib/amaze/formatter/image.rb +127 -0
  37. data/lib/amaze/formatter/image/delta.rb +123 -0
  38. data/lib/amaze/formatter/image/ortho.rb +103 -0
  39. data/lib/amaze/formatter/image/polar.rb +173 -0
  40. data/lib/amaze/formatter/image/sigma.rb +122 -0
  41. data/lib/amaze/formatter/image/upsilon.rb +135 -0
  42. data/lib/amaze/grid.rb +66 -0
  43. data/lib/amaze/grid/delta.rb +87 -0
  44. data/lib/amaze/grid/ortho.rb +38 -0
  45. data/lib/amaze/grid/polar.rb +61 -0
  46. data/lib/amaze/grid/sigma.rb +61 -0
  47. data/lib/amaze/grid/upsilon.rb +74 -0
  48. data/lib/amaze/mask.rb +75 -0
  49. data/lib/amaze/masked_grid.rb +29 -0
  50. data/lib/amaze/script.rb +361 -0
  51. data/lib/amaze/shape.rb +23 -0
  52. data/lib/amaze/shape/diamond.rb +26 -0
  53. data/lib/amaze/shape/hexagon.rb +79 -0
  54. data/lib/amaze/shape/star.rb +114 -0
  55. data/lib/amaze/shape/triangle.rb +25 -0
  56. data/lib/amaze/version.rb +3 -0
  57. data/support/characters.txt +17 -0
  58. data/support/mask/mask1.txt +10 -0
  59. data/support/mask/mask2.txt +12 -0
  60. data/support/mask/mask3.txt +15 -0
  61. metadata +203 -0
@@ -0,0 +1,5 @@
1
+
2
+ module Amaze::Formatter
3
+ autoload :ASCII, 'amaze/formatter/ascii'
4
+ autoload :Image, 'amaze/formatter/image'
5
+ end
@@ -0,0 +1,91 @@
1
+
2
+ # all rainbow colors: Rainbow::X11ColorNames::NAMES.keys
3
+ require 'rainbow/ext/string'
4
+
5
+ class Amaze::Formatter::ASCII
6
+ autoload :Delta, 'amaze/formatter/ascii/delta'
7
+ autoload :Ortho, 'amaze/formatter/ascii/ortho'
8
+ autoload :Sigma, 'amaze/formatter/ascii/sigma'
9
+ autoload :Upsilon, 'amaze/formatter/ascii/upsilon'
10
+ autoload :Polar, 'amaze/formatter/ascii/polar'
11
+
12
+ # The grid
13
+ attr_reader :grid
14
+
15
+ # Options for the ASCII renderer
16
+ attr_reader :options
17
+
18
+ def initialize grid, options={}
19
+ @grid = grid
20
+ @options = options
21
+ end
22
+
23
+ def char
24
+ @char ||= Array.new(char_array_height) do |x|
25
+ Array.new(char_array_width) do |y|
26
+ clear
27
+ end
28
+ end
29
+ end
30
+
31
+ def render
32
+ grid.each_cell do |cell|
33
+ draw_cell cell
34
+ draw_content cell if distances
35
+ draw_path cell if path_cell? cell
36
+ end
37
+
38
+ ansi_clear + char.map{|l| l.join }.join("\n")
39
+ end
40
+
41
+ def path? direction, cell
42
+ cell.linked?(cell.send(direction)) && path_cell?(cell.send(direction))
43
+ end
44
+
45
+ def ansi_clear
46
+ "\e[H\e[2J"
47
+ end
48
+
49
+ def clear
50
+ ' '
51
+ end
52
+
53
+ # The size of the cell
54
+ def cell_size
55
+ options[:cell_size] || 1
56
+ end
57
+
58
+ # The color of the grid
59
+ def grid_color
60
+ options[:grid_color] || :white
61
+ end
62
+
63
+ # The color used to draw the solution or the longest path
64
+ def path_color
65
+ options[:path_color] || :blue
66
+ end
67
+
68
+ def path_cell? cell
69
+ Array(options[:path_cells]).include? cell
70
+ end
71
+
72
+ # Distances
73
+ def distances
74
+ options[:distances]
75
+ end
76
+
77
+ def distance cell
78
+ # .to_s(36) => 0..9a..z
79
+ distances && distances[cell] ? distances[cell].to_s(36).upcase : ' '
80
+ end
81
+
82
+ def distance_color cell
83
+ return @options[:distances_color] if @options[:distances_color]
84
+ _, max = distances.max
85
+ high = (255-47).to_f / max * distances[cell] + 47
86
+ low = high / 4
87
+ p [:low, low] unless (0..255).include? low
88
+ p [:high, high] unless (0..255).include? high
89
+ [0,low,high]
90
+ end
91
+ end
@@ -0,0 +1,180 @@
1
+
2
+ class Amaze::Formatter::ASCII::Delta < Amaze::Formatter::ASCII
3
+
4
+ def draw_cell cell
5
+ x0, y0 = coord cell
6
+
7
+ # reverse triangle
8
+ if (cell.column + cell.row).even?
9
+ # corner
10
+ char[y0][x0] = corner.color(grid_color)
11
+ char[y0][x0+(cell_size+1)*2] = corner.color(grid_color)
12
+ char[y0+cell_size+1][x0+cell_size+1] = corner.color(grid_color)
13
+
14
+ 0.upto(cell_size*2) do |i|
15
+ # north
16
+ char[y0][x0+1+i] = h.color(grid_color)
17
+ end unless cell.linked_to?(:north)
18
+ 1.upto(cell_size) do |i|
19
+ # west
20
+ char[y0+i][x0+i] = rw.color(grid_color) unless cell.linked_to?(:west)
21
+ # east
22
+ char[y0+i][x0+(cell_size+1)*2-i] = re.color(grid_color) unless cell.linked_to?(:east)
23
+ end
24
+
25
+ # normal triangle
26
+ else
27
+ # corner
28
+ char[y0+cell_size+1][x0] = corner.color(grid_color)
29
+ char[y0+cell_size+1][x0+(cell_size+1)*2] = corner.color(grid_color)
30
+ char[y0][x0+cell_size+1] = corner.color(grid_color)
31
+
32
+ 0.upto(cell_size*2) do |i|
33
+ # south
34
+ char[y0+cell_size+1][x0+1+i] = h.color(grid_color)
35
+ end unless cell.linked_to?(:south)
36
+ 1.upto(cell_size) do |i|
37
+ # west
38
+ char[y0+i][x0+cell_size+1-i] = nw.color(grid_color) unless cell.linked_to?(:west)
39
+ # east
40
+ char[y0+i][x0+cell_size+1+i] = ne.color(grid_color) unless cell.linked_to?(:east)
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ def draw_content cell
47
+ x0, y0 = coord cell
48
+
49
+ if cell_size == 1
50
+ my = y0 + 1
51
+ mx = x0 + 2
52
+ w = 1
53
+ else
54
+ mx = x0 + cell_size / 2 + 1
55
+ w = (cell_size+1) / 2 * 2 + 1
56
+ if (cell.column+cell.row).even?
57
+ my = y0 + cell_size / 2
58
+ else
59
+ my = y0 + (cell_size+3) / 2
60
+ end
61
+ end
62
+
63
+ distance(cell).center(w).chars.each_with_index do |c,i|
64
+ char[my][mx+i] = c.color(*distance_color(cell))
65
+ end
66
+ end
67
+
68
+ def draw_path cell
69
+ x0, y0 = coord cell
70
+
71
+ mx = x0 + cell_size + 1
72
+ my = y0 + (cell_size + 1) / 2
73
+
74
+ # center
75
+ char[my][mx] = center.color(path_color)
76
+ 1.upto(cell_size) do |i|
77
+ # east-west
78
+ char[my][mx+i] = h.color(path_color) if path?(:east, cell)
79
+ # north-south
80
+ char[my+i][mx] = v.color(path_color) if path?(:south, cell)
81
+ end
82
+ end
83
+
84
+ def coord cell
85
+ [xpos(cell.column), ypos(cell.row)]
86
+ end
87
+
88
+ def xpos column
89
+ (cell_size + 1) * column
90
+ end
91
+
92
+ def ypos row
93
+ (cell_size + 1) * row
94
+ end
95
+
96
+ def char_array_width
97
+ xpos(grid.columns + 1) + 1
98
+ end
99
+
100
+ def char_array_height
101
+ ypos(grid.rows) + 1
102
+ end
103
+
104
+ def h
105
+ '-'
106
+ end
107
+
108
+ def v
109
+ '|'
110
+ end
111
+
112
+ def rw
113
+ '\\'
114
+ end
115
+
116
+ def re
117
+ '/'
118
+ end
119
+
120
+ def corner
121
+ '∙'
122
+ end
123
+
124
+ alias_method :center, :corner
125
+ alias_method :nw, :re
126
+ alias_method :ne, :rw
127
+
128
+ end
129
+
130
+ __END__
131
+
132
+ ∙---∙---∙
133
+ \...\ / \
134
+ ∙ . ∙---∙
135
+ / \./ \ /
136
+ ∙---∙---∙
137
+ \ / \ / \
138
+ ∙---∙---∙
139
+
140
+ ∙-----∙-----∙
141
+ \ ....\ * / \
142
+ \ . \ / \
143
+ ∙ . ∙-----∙
144
+ /.... / \ /
145
+ / . / \ /
146
+ ∙ . ∙-----∙
147
+ \ . / \ / \
148
+ \ / \ / \
149
+ ∙-----∙-----∙
150
+
151
+ ∙-------∙-------∙
152
+ \ \ / \
153
+ \ ..... \ / \
154
+ \ . \ / \
155
+ ∙ . ∙-------∙
156
+ / \ . / \ /
157
+ / \ / \ /
158
+ / \ / \ /
159
+ ∙-------∙-------∙
160
+ \ / \ / \
161
+ \ / \ / \
162
+ \ / \ / \
163
+ ∙-------∙-------∙
164
+
165
+ ∙---------∙---------∙
166
+ \ / \ / \
167
+ \ . \ / \
168
+ \ ` . \ / \
169
+ \ / \ / \
170
+ ∙---------∙---------∙
171
+ / \ / \ /
172
+ / \ / \ /
173
+ / \ / \ /
174
+ / \ / \ /
175
+ ∙---------∙---------∙
176
+ \ / \ / \
177
+ \ / \ / \
178
+ \ / \ / \
179
+ \ / \ / \
180
+ ∙---------∙---------∙
@@ -0,0 +1,105 @@
1
+
2
+ class Amaze::Formatter::ASCII::Ortho < Amaze::Formatter::ASCII
3
+
4
+ def draw_cell cell
5
+ left, right, top, bottom = coord cell
6
+
7
+ # corners
8
+ char[top][left] = corner.color(grid_color)
9
+ char[top][right] = corner.color(grid_color)
10
+ char[bottom][left] = corner.color(grid_color)
11
+ char[bottom][right] = corner.color(grid_color)
12
+ # top & bottom
13
+ (left+1).upto(right-1) do |i|
14
+ # top
15
+ char[top][i] = h.color(grid_color) unless cell.linked_to?(:north)
16
+ # bottom
17
+ char[bottom][i] = h.color(grid_color) unless cell.linked_to?(:south)
18
+ end
19
+ # left & right
20
+ (top+1).upto(bottom-1) do |i|
21
+ # left
22
+ char[i][left] = v.color(grid_color) unless cell.linked_to?(:west)
23
+ # right
24
+ char[i][right] = v.color(grid_color) unless cell.linked_to?(:east)
25
+ end
26
+ end
27
+
28
+ def draw_content cell
29
+ left, right, top, bottom = coord cell
30
+
31
+ my = top + cell_size / 2 + 1
32
+ distance(cell).center(cell_size * 3).chars.each_with_index do |c,i|
33
+ char[my][left+1+i] = c.color(*distance_color(cell))
34
+ end
35
+ end
36
+
37
+ def draw_path cell
38
+ left, right, top, bottom = coord cell
39
+
40
+ mx = left + (cell_size * 3 + 1) / 2
41
+ my = top + cell_size / 2 + 1
42
+
43
+ # TODO: simplify paths, draw only north-south and east-west
44
+
45
+ # to north
46
+ top.upto(my-1) do |i|
47
+ char[i][mx] = v.color(path_color) if path?(:north, cell)
48
+ end if top <= my-1
49
+ # to east
50
+ (mx+1).upto(right) do |i|
51
+ char[my][i] = h.color(path_color) if path?(:east, cell)
52
+ end if mx+1 <= right
53
+ # to south
54
+ (my+1).upto(bottom) do |i|
55
+ char[i][mx] = v.color(path_color) if path?(:south, cell)
56
+ end if my+1 <= bottom
57
+ # to west
58
+ left.upto(mx-1) do |i|
59
+ char[my][i] = h.color(path_color) if path?(:west, cell)
60
+ end if left <= mx-1
61
+ # center, select the char depeding on how many paths cross the cell
62
+ center_char = center
63
+ center_char = v if path?(:north, cell) && path?(:south, cell)
64
+ center_char = h if path?(:east, cell) && path?(:west, cell)
65
+ center_char = corner if [:north, :east, :south, :west].select{|d| path?(d, cell) }.size >= 3
66
+ char[my][mx] = center_char.color(path_color)
67
+ end
68
+
69
+ # left, right, top, bottom
70
+ def coord cell
71
+ [x(cell.column), x(cell.column+1), y(cell.row), y(cell.row+1)]
72
+ end
73
+
74
+ def x column
75
+ (cell_size * 3 + 1) * column
76
+ end
77
+
78
+ def y row
79
+ (cell_size + 1) * row
80
+ end
81
+
82
+ def char_array_width
83
+ x(grid.columns) + 1
84
+ end
85
+
86
+ def char_array_height
87
+ y(grid.rows) + 1
88
+ end
89
+
90
+ def h
91
+ '-'
92
+ end
93
+
94
+ def v
95
+ '|'
96
+ end
97
+
98
+ def center
99
+ '∙'
100
+ end
101
+
102
+ def corner
103
+ '+'
104
+ end
105
+ end
@@ -0,0 +1,199 @@
1
+
2
+ class Amaze::Formatter::ASCII::Polar < Amaze::Formatter::ASCII
3
+
4
+ def draw_cell cell
5
+ x1, x2, y1, y2 = coord cell
6
+
7
+ # corners
8
+ char[y1][x1] = corner.color(grid_color)
9
+ char[y1][x2] = corner.color(grid_color)
10
+ char[y2][x1] = corner.color(grid_color)
11
+ char[y2][x2] = corner.color(grid_color)
12
+ # top & bottom
13
+ (x1+1).upto(x2-1) do |i|
14
+ # top (inward)
15
+ char[y1][i] = h.color(grid_color) unless cell.linked_to?(:inward)
16
+ # bottom (outward)
17
+ char[y2][i] = h.color(grid_color) if cell.row == grid.rows-1
18
+ end
19
+ # left & right
20
+ (y1+1).upto(y2-1) do |i|
21
+ # left (cw)
22
+ char[i][x1] = v.color(grid_color) unless cell.linked_to?(:cw)
23
+ # right (ccw)
24
+ char[i][x2] = v.color(grid_color) unless cell.linked_to?(:ccw)
25
+ end
26
+ end
27
+
28
+ def draw_content cell
29
+ x1, x2, y1, y2 = coord cell
30
+ _, my = center_coord cell
31
+ dx = x2 - x1 - 1
32
+
33
+ distance(cell).center(dx).chars.each_with_index do |c,i|
34
+ char[my][x1+1+i] = c.color(*distance_color(cell))
35
+ end
36
+ end
37
+
38
+ def draw_path cell
39
+ # draw horizontal connections in cells with more than one outward path
40
+ if outward_subdivided?(cell) && ! path?(:cw, cell) && ! path?(:ccw, cell)
41
+ outward_cells = path_outward(cell)
42
+ if outward_cells.any?
43
+ mx, my = center_coord cell
44
+ x_outward_cells = outward_cells.map{|c| x,_ = center_coord c; x}
45
+ mx = x_outward_cells.first if cell.row.zero?
46
+ mx_min = [mx, *x_outward_cells].min
47
+ mx_max = [mx, *x_outward_cells].max
48
+ char[my][mx_min] = center.color(path_color)
49
+ char[my][mx_max] = center.color(path_color)
50
+ (mx_min+1).upto(mx_max-1) do |i|
51
+ char[my][i] = h.color(path_color)
52
+ end
53
+ end
54
+ end
55
+
56
+ # to cw
57
+ if path?(:cw, cell)
58
+ mx1, my1 = center_coord cell.cw
59
+ mx2, my2 = center_coord cell
60
+ if outward_subdivided? cell
61
+ outward_cells_cw = path_outward cell.cw
62
+ mx1, _ = center_coord(outward_cells_cw.first) if outward_cells_cw.any?
63
+ outward_cells = path_outward cell
64
+ mx2, _ = center_coord(outward_cells.first) if outward_cells.any?
65
+ end
66
+ mx1 = -1 if mx1 > mx2
67
+ (mx1+1).upto(mx2-1) do |i|
68
+ char[my1][i] = h.color(path_color)
69
+ end
70
+ char[my1][mx2] = center.color(path_color)
71
+ end
72
+
73
+ # to ccw
74
+ if path?(:ccw, cell)
75
+ mx1, my1 = center_coord cell
76
+ mx2, my2 = center_coord cell.ccw
77
+ if outward_subdivided? cell
78
+ outward_cells = path_outward cell
79
+ mx1, _ = center_coord(outward_cells.first) if outward_cells.any?
80
+ outward_cells_ccw = path_outward cell.ccw
81
+ mx2, _ = center_coord(outward_cells_ccw.first) if outward_cells_ccw.any?
82
+ end
83
+ mx2 = char_array_width if mx1 > mx2
84
+ (mx1+1).upto(mx2-1) do |i|
85
+ char[my1][i] = h.color(path_color)
86
+ end
87
+ char[my1][mx1] = center.color(path_color)
88
+ end
89
+
90
+ # to inward
91
+ if path?(:inward, cell)
92
+ mx, my = center_coord cell
93
+ v1, v2, w1, w2 = coord cell.inward
94
+ mw = (w1 + w2) / 2
95
+ (mw+1).upto(my-1) do |i|
96
+ char[i][mx] = v.color(path_color)
97
+ end
98
+ end
99
+
100
+ # center
101
+ mx, my = center_coord cell
102
+ if outward_subdivided? cell
103
+ char[my][mx] = h.color(path_color) if path?(:ccw, cell) && path?(:cw, cell)
104
+ char[my][mx] = center.color(path_color) if path?(:inward, cell) && path_outward(cell).empty?
105
+ else
106
+ center_char = center
107
+ center_char = h if path?(:ccw, cell) && path?(:cw, cell)
108
+ center_char = v if path?(:inward, cell) && path_outward(cell).any?
109
+ char[my][mx] = center_char.color(path_color)
110
+ end
111
+ end
112
+
113
+ def outward_subdivided? cell
114
+ return false if grid.rows == cell.row + 1
115
+ grid.columns(cell.row).size != grid.columns(cell.row+1).size
116
+ end
117
+
118
+ def path_outward cell
119
+ cell.outward.select {|o| cell.linked?(o) && path_cell?(o) }
120
+ end
121
+
122
+ def coord cell
123
+ columns = grid.columns(cell.row).size
124
+ x2 = char_array_width - 1 - x(cell.column, columns)
125
+ x1 = char_array_width - 1 - x(cell.column+1, columns)
126
+ y1 = y(cell.row)
127
+ y2 = y(cell.row+1)
128
+
129
+ [x1, x2, y1, y2]
130
+ end
131
+
132
+ def center_coord cell
133
+ x1, x2, y1, y2 = coord cell
134
+ [(x1 + x2) / 2, (y1 + y2) / 2]
135
+ end
136
+
137
+ def x column, columns=max_columns
138
+ factor = max_columns / columns
139
+ (cell_size * 4 * factor) * column
140
+ end
141
+
142
+ def y row
143
+ (cell_size + 1) * row
144
+ end
145
+
146
+ def max_columns
147
+ grid.columns(grid.rows-1).size
148
+ end
149
+
150
+ def char_array_width
151
+ x(max_columns) + 1
152
+ end
153
+
154
+ def char_array_height
155
+ y(grid.rows) + 1
156
+ end
157
+
158
+ def h
159
+ '-'
160
+ end
161
+
162
+ def v
163
+ '|'
164
+ end
165
+
166
+ def center
167
+ '∙'
168
+ end
169
+
170
+ def corner
171
+ '+'
172
+ end
173
+ end
174
+
175
+ __END__
176
+
177
+ +-----------------------------------------------+ 47 f=12 columns/column * 3 + columns/column-1
178
+ | |
179
+ +---------------+---------------+---------------+ 15 f=4
180
+ | | | |
181
+ +-------+-------+-------+-------+-------+-------+ 7 f=2
182
+ | | | | | | |
183
+ +---+---+---+---+---+---+---+---+---+---+---+---+ 3 f=1
184
+ | | | | | | | | | | | | |
185
+ +---+---+---+---+---+---+---+---+---+---+---+---+
186
+
187
+ +-----------------------------------------------------------------------------------+
188
+ | |
189
+ | |
190
+ +---------------------------+---------------------------+---------------------------+
191
+ | | | |
192
+ | | | |
193
+ +-------------+-------------+-------------+-------------+-------------+-------------+
194
+ | | | | | | |
195
+ | | | | | | |
196
+ +------+------+------+------+------+------+------+------+------+------+------+------+
197
+ | | | | | | | | | | | | |
198
+ | | | | | | | | | | | | |
199
+ +------+------+------+------+------+------+------+------+------+------+------+------+