|
@@ -0,0 +1,146 @@
|
|
1
|
+#!usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+#############################
|
|
4
|
+# DRAWT00l -----------------#
|
|
5
|
+# An ASCII drawing tool that#
|
|
6
|
+# supports bucket fill.-----#
|
|
7
|
+#############################
|
|
8
|
+
|
|
9
|
+@paper= Array.new
|
|
10
|
+@instructions = Hash.new
|
|
11
|
+
|
|
12
|
+def canvas(width, height)
|
|
13
|
+ 0.upto(height+1) do |line|
|
|
14
|
+ #adding two extra lines to account for the top/bottom border
|
|
15
|
+ if line == 0
|
|
16
|
+ #top horizontal border
|
|
17
|
+ @paper[line]='-'*(width+2)
|
|
18
|
+ elsif line == (height+1)
|
|
19
|
+ #bottom horizontal border
|
|
20
|
+ @paper[line]='-'*(width+2)
|
|
21
|
+ else
|
|
22
|
+ #draw inside the canvas/box
|
|
23
|
+ inside = " " * (width)
|
|
24
|
+ @paper[line]="|"+"#{inside}"+"|"
|
|
25
|
+ end
|
|
26
|
+ end
|
|
27
|
+end
|
|
28
|
+
|
|
29
|
+def create_line(coords)
|
|
30
|
+ coord_array = coords.split
|
|
31
|
+ if coord_array[1] == coord_array[3]
|
|
32
|
+ #we are doing a horizontal line
|
|
33
|
+ (coord_array[0]..coord_array[2]).each do |x|
|
|
34
|
+ @paper[(coord_array[1].to_i)][x.to_i] = "x"
|
|
35
|
+ end
|
|
36
|
+ elsif coord_array[0] == coord_array[2]
|
|
37
|
+ #we are doing a vertical line
|
|
38
|
+ (coord_array[1]..coord_array[3]).each do |y|
|
|
39
|
+ @paper[(y.to_i)][coord_array[0].to_i] = "x"
|
|
40
|
+ end
|
|
41
|
+ else
|
|
42
|
+ #catch error
|
|
43
|
+ raise 'error: Mismatching x and y coordinates'
|
|
44
|
+ end
|
|
45
|
+end
|
|
46
|
+
|
|
47
|
+def create_rectangle(coords)
|
|
48
|
+ coord_array = coords.split
|
|
49
|
+ #lets make use of the create_line method using the provided coords we can draw each line of the rectangle.
|
|
50
|
+ top_side = coord_array[0] + " " + coord_array[1] + " " + coord_array[2] + " " + coord_array[1]
|
|
51
|
+ bottom_side = coord_array[0] + " " + coord_array[3] + " " + coord_array[2] + " " + coord_array[3]
|
|
52
|
+ left_side = coord_array[0] + " " + coord_array[1] + " " + coord_array[0] + " " + coord_array[3]
|
|
53
|
+ right_side = coord_array[2] + " " + coord_array[1] + " " + coord_array[2] + " " + coord_array[3]
|
|
54
|
+ #we have all of the sides, now lets draw them using the create_line method
|
|
55
|
+ %w(top_side bottom_side left_side right_side).each do |side|
|
|
56
|
+ create_line(eval(side))
|
|
57
|
+ end
|
|
58
|
+end
|
|
59
|
+
|
|
60
|
+def bucket_fill(options)
|
|
61
|
+ x, y, c = options.split
|
|
62
|
+ #set vars to int to makes things easier
|
|
63
|
+ x, y = x.to_i, y.to_i
|
|
64
|
+ #start_c holds the original "color", we will use this to compare againts
|
|
65
|
+ start_c = @paper[y][x]
|
|
66
|
+ #we need to do some math, so lets gather the width and height of the "paper"
|
|
67
|
+ width = @paper[y].length
|
|
68
|
+ height = @paper.length
|
|
69
|
+ #create an empty array to store the areas we want to fill/color
|
|
70
|
+ area_fill = []
|
|
71
|
+ #to get started lets see if our x,y coords match start_c with our "color", if it does not add it to the area_fill array
|
|
72
|
+ area_fill << [x, y] unless start_c == c
|
|
73
|
+
|
|
74
|
+ #while loop will continue until fill array is empty
|
|
75
|
+ while area_fill.any?
|
|
76
|
+ #pop aka remove coords from area_fill to prevent from doing duplicate work
|
|
77
|
+ x, y = area_fill.pop
|
|
78
|
+ #if coords match the starting color lets fill that area
|
|
79
|
+ next unless !@paper[y].nil? && @paper[y][x] == start_c
|
|
80
|
+ @paper[y][x] = c
|
|
81
|
+ #now lets add the area around the coords to area_fill
|
|
82
|
+ #using bitwise operator to append uniq coords to array
|
|
83
|
+ #perfoming modular operation for ease of collection north,south,east,west coords
|
|
84
|
+ area_fill |= [[(x-1) % width, y],[(x+1) % width, y],[x,(y-1) % height],[x,(y+1) % height]]
|
|
85
|
+ end
|
|
86
|
+end
|
|
87
|
+
|
|
88
|
+def read_input(file_path)
|
|
89
|
+ if File.exist? file_path
|
|
90
|
+ #count to keep keys uniq / unless "C" we should only have one
|
|
91
|
+ line = 1
|
|
92
|
+ File.foreach(file_path).each do |x|
|
|
93
|
+ unless x[0] == "C"
|
|
94
|
+ @instructions[x[0]+line.to_s] =x[1..-1].strip
|
|
95
|
+ line += 1
|
|
96
|
+ else
|
|
97
|
+ @instructions[x[0]] =x[1..-1].strip
|
|
98
|
+ end
|
|
99
|
+ end
|
|
100
|
+ else
|
|
101
|
+ raise 'error: Input file not found/missing!'
|
|
102
|
+ end
|
|
103
|
+ #Make sure we have intructions to create a canvas before starting
|
|
104
|
+ unless @instructions.flatten.include? 'C'
|
|
105
|
+ raise 'error: Missing canvas "C" instructions.We need to know the Height and Width of area we are working with'
|
|
106
|
+ end
|
|
107
|
+end
|
|
108
|
+
|
|
109
|
+def write_output(output_file)
|
|
110
|
+ begin
|
|
111
|
+ file = File.open(output_file,'a')
|
|
112
|
+ file.puts(@paper)
|
|
113
|
+ rescue
|
|
114
|
+ raise "error: IO FAIL"
|
|
115
|
+ ensure
|
|
116
|
+ file.close()
|
|
117
|
+ end
|
|
118
|
+end
|
|
119
|
+
|
|
120
|
+#read arguments provided by user using read_input method also check that we have both input/output files
|
|
121
|
+unless ARGV.empty? && ARGV.count != 2
|
|
122
|
+ read_input(ARGV[0])
|
|
123
|
+else
|
|
124
|
+ raise 'warning: Missing input and output files'
|
|
125
|
+end
|
|
126
|
+
|
|
127
|
+#DRAWWWWW
|
|
128
|
+begin
|
|
129
|
+ @instructions.each_key do |c|
|
|
130
|
+ if c == "C"
|
|
131
|
+ canvas(@instructions[c].split[0].to_i, @instructions[c].split[1].to_i)
|
|
132
|
+ write_output(ARGV[1])
|
|
133
|
+ elsif c =~/L/i
|
|
134
|
+ create_line(@instructions[c])
|
|
135
|
+ write_output(ARGV[1])
|
|
136
|
+ elsif c =~/R/i
|
|
137
|
+ create_rectangle(@instructions[c])
|
|
138
|
+ write_output(ARGV[1])
|
|
139
|
+ elsif c =~/B/i
|
|
140
|
+ bucket_fill(@instructions[c])
|
|
141
|
+ write_output(ARGV[1])
|
|
142
|
+ end
|
|
143
|
+ end
|
|
144
|
+ rescue
|
|
145
|
+ raise "error: Are your coordinates in rage of #{@paper[0].length.pred.pred} by #{@paper.length.pred.pred}"
|
|
146
|
+end
|