vamp 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3ed0c28b4a5fa22a09ccafc6674d51076fb75816
4
- data.tar.gz: 931968ca87c4c1cf6c4c5a4b8865625bece04ec0
3
+ metadata.gz: 4c4315d0432b085681e7afa71522bfc0fe3e04f3
4
+ data.tar.gz: 591b310d5939ddfa3070a867b54f8c603092e72f
5
5
  SHA512:
6
- metadata.gz: b196797bc06e8c60be048e59a4a9a11bcbf8fdece181c07d3e0832afd61616f79aee6caa725380f58b4be0bc61a6f04c72dde40dd5a8cfd33debf0c5fb1db91f
7
- data.tar.gz: e122c443482653ceaa831f2dad9a6d84a010dd2040e710c89b159b6a6bbc5803d4ffb0738ed2fec214c9fb8da6b1cba24a307f03b3cd2bb998f0415310d6605b
6
+ metadata.gz: 16383a97ea438b01e28dc035290fc1d5ed58952f516a70df23a702088a2d323c138b475e5dd91a5e7653ba57b6d57d241e49ceac634e794f9f651a2df48868b2
7
+ data.tar.gz: f831bae4c7f817ac9fc073fdefd45ff0f8a5dd48bc868709c0cb4a634d4ee91e37ce0b141ba1ab3dc10ba8f1ada633aca1f6e173db5ced106dfcbabaa51f3614
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  /.idea/
3
3
  /.yardoc
4
4
  /Gemfile.lock
5
+ /*.gem
5
6
  /_yardoc/
6
7
  /coverage/
7
8
  /doc/
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Vamp - necessities for the elegant vampire
2
2
 
3
3
  Want to pimp up your command line interface?
4
- Just require this gem insert some code and your CLI makes witty vampire quotes.
4
+ Just require this gem, insert some code and your CLI makes witty vampire quotes.
5
+ You can even play animated ascii art in a console window.
5
6
 
6
7
  ## Installation
7
8
 
@@ -19,10 +20,9 @@ Or install it yourself as:
19
20
 
20
21
  $ gem install vamp
21
22
 
22
- ## Usage
23
+ ## Usage with thor
23
24
 
24
25
  ```ruby
25
-
26
26
  require "thor"
27
27
  require "vamp"
28
28
 
@@ -53,6 +53,23 @@ end
53
53
  CLI.start(ARGV)
54
54
  ```
55
55
 
56
+ ## Animation Usage
57
+
58
+ You can play an ascii art animation within a terminal window by using vamp.
59
+
60
+ ```ruby
61
+ require "vamp"
62
+
63
+ animator = Vamp::Animator.new(File.join(Gem.loaded_specs["vamp"].gem_dir, "files", "vampire.txt"), 31, 0, 24,
64
+ "No man knows till he has suffered from the night how sweet and how dear to his heart and eye the morning can be.")
65
+ animator.play
66
+ ```
67
+
68
+ To see the animation in higher resolution just click on the following image.
69
+
70
+ [![Animation Demo](https://raw.githubusercontent.com/m-31/vamp/data/pic/demo_001.gif)](https://raw.githubusercontent.com/m-31/vamp/data/pic/demo_001.mp4)
71
+
72
+
56
73
  ## Development
57
74
 
58
75
  After checking out the repo, run `bundle install` to install dependencies.
data/lib/vamp/art.rb ADDED
@@ -0,0 +1,189 @@
1
+ module Vamp
2
+ module Art
3
+
4
+ def self.remove_ansi(text)
5
+ text.gsub(/[\[\d;]+m/, '')
6
+ end
7
+
8
+ # ascii art by the queen of ascii art: Joan Stark (jgs)
9
+ # https://en.wikipedia.org/wiki/Joan_Stark
10
+ VAMPIRE = <<-'END'
11
+ =/\ /\=
12
+ / \'._ (\_/) _.'/ \
13
+ / .''._'--(o.o)--'_.''. \
14
+ /.' _/ |`'=/ " \='`| \_ `.\
15
+ /` .' `\;-,'\___/',-;/` '. '\
16
+ /.-' jgs `\(-V-)/` `-.\
17
+ ` " " `
18
+ END
19
+ HOBGOBLIN_COLOR = <<-'END'
20
+  , _.._ ,
21
+ (`._."` `"._.')
22
+ '._ _.' /\
23
+ | /`-. .-'\ | __ .'.'
24
+ |(_()_\/_()_)|' `\ ( (
25
+ ; ,____, ; \ ) )
26
+ \ /VvvV\ / \ \.__ / /
27
+ /`'._`""`_.' \ \ `\/ /
28
+ / . `--' \ \ /
29
+ / / `-, _.----' \ ;
30
+ / / ) / .--------` \
31
+ / /.----' / / ___. \
32
+ / /| _ _,| (---' \ |
33
+ / / | \`""` \\\\ \ |
34
+ / /` | | \\\` \ \
35
+ / / ; | / /
36
+ / / _ \ / /` /`
37
+ / _\/( | | / .'_
38
+ | ( \ '--' \ .' (__)`\
39
+ \\\\ `-------' jgs /________.'
40
+ `\\\
41
+ 
42
+ END
43
+ HOBGOBLIN = remove_ansi(HOBGOBLIN_COLOR)
44
+ SHARK_COLOR = <<-'END'
45
+  o
46
+  ___.. ,
47
+  __..--''__ ( .';
48
+  o __.-------.-' `--..__ .' ;
49
+  _.--' 0) .--._ ``--...____.' .'
50
+  ( _. )). .__.-'' <
51
+  `````---....._____.....- -..___ _____...--'-.'.
52
+  jgs `-.___.' ``````` `.;
53
+ 
54
+ END
55
+ SHARK = remove_ansi(SHARK_COLOR)
56
+ DRAGON_COLOR = <<-'END'
57
+   ___ ___
58
+  ,_;-'-._\__/_.-'
59
+  ,_\ a\/a
60
+  ,_\ ,-( _'-._
61
+ ,_\ (==/\ |'-._\
62
+  ,_\ -. /\ \/ | |\ `
63
+  ,_\ \/==\ '._\7 '._
64
+ jgs '. '._ \=/\'-}}} '-}}}
65
+  / /> /` )
66
+ |\_.' .'( <_ <_
67
+ \____.-' '--}}}-}}}
68
+ 
69
+ END
70
+ DRAGON = remove_ansi(DRAGON_COLOR)
71
+
72
+ # ascii art by Daniel Au (dcau)
73
+ # http://www.oocities.org/SoHo/7373/dcau.htm
74
+ SKULL_COLOR = <<-'END'
75
+  _,.-------.,_
76
+ ,;~' '~;,
77
+ ,; ;,
78
+ ; ;
79
+ ,' ',
80
+ ,; ;,
81
+ ; ; . . ; ;
82
+ | ; ______ ______ ; |
83
+ | `/~" ~" . "~ "~\' |
84
+ | ~ ,-~~~^~, | ,~^~~~-, ~ |
85
+ | | }:{ | |
86
+ | l / | \ ! |
87
+ .~ (__,.--" .^. "--.,__) ~.
88
+ | ---;' / | \ `;--- |
89
+ \__. \/^\/ .__/
90
+ V| \ / |V
91
+ | |T~\___!___!___/~T| |
92
+ | |`IIII_I_I_I_IIII'| |
93
+ | \,III I I I III,/ |
94
+ \ `~~~~~~~~~~' /
95
+ \ . . / -dcau
96
+ \. ^ ./
97
+ ^~~~^~~~^
98
+ 
99
+ END
100
+ SKULL = remove_ansi(SKULL_COLOR)
101
+
102
+ # acii art by Andreas Freise (a:f)
103
+ # http://www.ascii-art.de/
104
+ LIZARD_COLOR = <<-'END'
105
+  )/_
106
+ _.--..---"-,--c_
107
+ \L..' ._O__)_
108
+ ,-. _.+ _ \..--( / a:f
109
+ `\.-''__.-' \ ( \_
110
+ `''' `\__ /\
111
+ ')
112
+ 
113
+ END
114
+ LIZARD = remove_ansi(LIZARD_COLOR)
115
+
116
+ # ascii art by Nico Okha (mOm)
117
+ RUNNING = <<-'END'
118
+ _
119
+ _( }
120
+ /_ )
121
+ / "/
122
+ / -;\
123
+ ;--' ´ /'
124
+ <_
125
+ END
126
+ DECLARING = <<-'END'
127
+ ,
128
+ (}_/
129
+ /,;
130
+ "^/ \
131
+ \|/
132
+ //
133
+ ""`
134
+ END
135
+
136
+ DECLARING2 = <<-'END'
137
+ !
138
+ ||
139
+ !|
140
+ | \ _
141
+ | \ /~ ~\
142
+ \ \_ /<- ->\
143
+ \ \_\.O.|\\
144
+ \ ' /__"
145
+ | \
146
+ \ ' . \ \
147
+ \ /) >
148
+ \ , | /
149
+ | \__/ <
150
+ > /o |)
151
+ / T /
152
+ / | /
153
+ / | . /
154
+ \/ \/ \
155
+ \ \ \
156
+ \ \ \
157
+ \ > \
158
+ /^ / ^\
159
+ ^^^~ ~~~mOm
160
+ END
161
+ GREEK = <<-'END'
162
+ ___
163
+ /. `\
164
+ / , ` |
165
+ /^\__/'
166
+ _,--~, /_
167
+ /' ~~~ -__ ~-,
168
+ ,/ , _ \
169
+ / |`-_ _ '_/%\ `\
170
+ / |_, ~~ __/`\ \
171
+ ,--~~"' / \ `--/ |, >
172
+ //^|~~---' ; , , | '
173
+ ,'` , ( | /
174
+ ,' `;;;,' \ ,' |
175
+ / 77); `./||`
176
+ / ,"^ \, ,
177
+ / / \ ,
178
+ ( ,' \ |
179
+ \ `. \_- \
180
+ \ ; \ `,
181
+ ` ' \ |
182
+ \ ` \ `
183
+ | ) `, `.
184
+ / ' ,' )
185
+ mooO' Ooom' mOm
186
+
187
+ END
188
+ end
189
+ end
@@ -0,0 +1,142 @@
1
+ require "forwardable"
2
+ require_relative "dotter"
3
+ require_relative "text_dotter"
4
+ require_relative "transfer"
5
+ require_relative "transfer5"
6
+
7
+ module Vamp
8
+ module Graphic
9
+ # Graphic Context
10
+ class Context
11
+ extend Forwardable
12
+
13
+ def_delegators :@dotter, :dot, :dot?, :undot, :in?, :clear, :screen, :width, :height
14
+
15
+ attr_reader :dotter # can set a dot within [0, width] [0, height[]]
16
+
17
+ def initialize(dotter)
18
+ @dotter = dotter
19
+ end
20
+
21
+ # Cohen–Sutherland clipping algorithm clips a line from
22
+ # P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
23
+ # diagonal from (xmin, ymin) to (xmax, ymax).
24
+ def line(x0, y0, x1, y1)
25
+ xmin = 0.0
26
+ ymin = 0.0
27
+ xmax = width - 1.0
28
+ ymax = height - 1.0
29
+
30
+ # compute outcodes for P0, P1, and whatever point lies outside the clip rectangle
31
+ outcode0 = compute_out_code(x0, y0)
32
+ outcode1 = compute_out_code(x1, y1)
33
+
34
+ accept = false
35
+
36
+ while true
37
+ if 0 == (outcode0 | outcode1) # Bitwise OR is 0. Trivially accept and get out of loop
38
+ accept = true
39
+ break
40
+ elsif 0 != (outcode0 & outcode1) # Bitwise AND is not 0. Trivially reject and get out of loop
41
+ break
42
+ else
43
+ # failed both tests, so calculate the line segment to clip
44
+ # from an outside point to an intersection with clip edge
45
+
46
+ # At least one endpoint is outside the clip rectangle; pick it.
47
+ outcodeOut = outcode0 != 0 ? outcode0 : outcode1
48
+
49
+
50
+ # Now find the intersection point;
51
+ # use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
52
+ if 0 != (outcodeOut & TOP) # point is above the clip rectangle
53
+ x = x0.to_f + (x1 - x0) * (ymax - y0) / (y1 - y0)
54
+ y = ymax
55
+ elsif (0 != outcodeOut & BOTTOM) # point is below the clip rectangle
56
+ x = x0.to_f + (x1 - x0) * (ymin - y0) / (y1 - y0)
57
+ y = ymin
58
+ elsif (0 != outcodeOut & RIGHT) # point is to the right of clip rectangle
59
+ y = y0.to_f + (y1 - y0) * (xmax - x0) / (x1 - x0)
60
+ x = xmax
61
+ elsif (0 != outcodeOut & LEFT) # point is to the left of clip rectangle
62
+ y = y0.to_f + (y1 - y0) * (xmin - x0) / (x1 - x0)
63
+ x = xmin
64
+ end
65
+
66
+ # Now we move outside point to intersection point to clip
67
+ # and get ready for next pass.
68
+ if outcodeOut == outcode0
69
+ x0 = x
70
+ y0 = y
71
+ outcode0 = compute_out_code(x0, y0)
72
+ else
73
+ x1 = x
74
+ y1 = y
75
+ outcode1 = compute_out_code(x1, y1)
76
+ end
77
+ end
78
+ end
79
+ if accept
80
+ draw_line_direct (x0 + 0.5).to_i, (y0 + 0.5).to_i, (x1 + 0.5).to_i, (y1 + 0.5).to_i
81
+ end
82
+ self
83
+ end
84
+
85
+ # protected
86
+
87
+ # Bresenham's line algorithm
88
+ def draw_line_direct(x0, y0, x1, y1)
89
+ dx = (x1 - x0).abs
90
+ sx = x0 < x1 ? 1 : -1
91
+ dy = -(y1 - y0).abs
92
+ sy = y0 < y1 ? 1 : -1
93
+ err = dx + dy
94
+ while true
95
+ dot(x0, y0)
96
+ break if x0 == x1 && y0 == y1
97
+ e2 = 2 * err
98
+ if e2 > dy
99
+ err += dy
100
+ x0 += sx
101
+ end
102
+ if e2 < dx
103
+ err += dx
104
+ y0 += sy
105
+ end
106
+ end
107
+ self
108
+ end
109
+
110
+ private
111
+
112
+ # clipping area constants
113
+ INSIDE = 0; # 0000
114
+ LEFT = 1; # 0001
115
+ RIGHT = 2; # 0010
116
+ BOTTOM = 4; # 0100
117
+ TOP = 8; # 1000
118
+
119
+ # Compute the bit code for a point (x, y) using the clip rectangle
120
+ # bounded diagonally by (xmin, ymin), and (xmax, ymax)
121
+ def compute_out_code(x, y)
122
+ xmin = 0
123
+ ymin = 0
124
+ xmax = width - 1
125
+ ymax = height - 1
126
+ code = INSIDE # initialised as being inside of clip window
127
+
128
+ if x < xmin # to the left of clip window
129
+ code |= LEFT
130
+ elsif x > xmax # to the right of clip window
131
+ code |= RIGHT
132
+ end
133
+ if y < ymin # below the clip window
134
+ code |= BOTTOM
135
+ elsif y > ymax # above the clip window
136
+ code |= TOP
137
+ end
138
+ code
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,53 @@
1
+ module Vamp
2
+ module Graphic
3
+ # basis class for graphic implementations
4
+ # you have to implement :dot, :undot, :clear and :screen
5
+ class Dotter
6
+ attr_reader :width # number of dots in x direction
7
+ attr_reader :height # number of dots in y direction
8
+
9
+ def initialize(width, height)
10
+ @width = width
11
+ @height = height
12
+ clear
13
+ end
14
+
15
+ # put dot at x, ys
16
+ def dot(x, y)
17
+ check(x, y)
18
+ self
19
+ end
20
+
21
+ # is there a dot at x, y
22
+ def dot?(x, y)
23
+ check(x, y)
24
+ end
25
+
26
+ # remove dot at x, y
27
+ def undot(x, y)
28
+ check(x, y)
29
+ self
30
+ end
31
+
32
+ # clear screen of all dots
33
+ def clear
34
+ self
35
+ end
36
+
37
+ # return complete screen as string representation
38
+ def screen
39
+ end
40
+
41
+ # check if (x, y) is on the screen
42
+ def in?(x, y)
43
+ (0...width) === x && (0...height) === y
44
+ end
45
+
46
+ # check if (x, y) is on the screen, fails if not
47
+ def check(x, y)
48
+ fail "for (#{x}, #{y}}: x not in [0, #{width}[" unless (0...width) === x
49
+ fail "for (#{x}, #{y}}: y not in [0, #{height}[" unless (0...height) === y
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,35 @@
1
+ require_relative "dotter"
2
+
3
+ module Vamp
4
+ module Graphic
5
+ # simple sample implementation for a graphic basic implementation
6
+ class TextDotter < Dotter
7
+ def dot(x, y)
8
+ super
9
+ @data[y][x] = "X"
10
+ self
11
+ end
12
+
13
+ def dot?(x, y)
14
+ super
15
+ @data[y][x] == "X"
16
+ end
17
+
18
+ def undot(x, y)
19
+ super
20
+ @data[y][x] = " "
21
+ self
22
+ end
23
+
24
+ def clear
25
+ @data = Array.new(height) { Array.new(width, " ") }
26
+ self
27
+ end
28
+
29
+ def screen
30
+ line = "+" + "-" * width + "+\n"
31
+ line + @data.map { |x| "|#{x.join('')}|" }.join("\n").to_s + "\n" + line
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,170 @@
1
+ module Vamp
2
+ module Graphic
3
+ # Transfer dotter data into ASCII
4
+ class Transfer
5
+
6
+ attr_reader :char_width
7
+ attr_reader :char_height
8
+ attr_reader :context
9
+ attr_reader :mapping
10
+
11
+ SPACE = <<-'END'
12
+ ___
13
+ ___
14
+ ___
15
+ END
16
+
17
+ SLASH = <<-'END'
18
+ __X
19
+ _X_
20
+ X__
21
+ END
22
+
23
+ BACKSLASH = <<-'END'
24
+ X__
25
+ _X_
26
+ __X
27
+ END
28
+
29
+ BACKTICK = <<-'END'
30
+ X__
31
+ ___
32
+ ___
33
+ END
34
+
35
+ PIPE = <<-'END'
36
+ _X_
37
+ _X_
38
+ _X_
39
+ END
40
+
41
+ MINUS = <<-'END'
42
+ ___
43
+ XXX
44
+ ___
45
+ END
46
+
47
+ UNDERSCORE = <<-'END'
48
+ ___
49
+ ___
50
+ XXX
51
+ END
52
+
53
+ FULLSTOP = <<-'END'
54
+ ___
55
+ ___
56
+ _X_
57
+ END
58
+
59
+ DOUBLEQUOTES = <<-'END'
60
+ X_X
61
+ ___
62
+ ___
63
+ END
64
+
65
+ SINGLEQUOTE = <<-'END'
66
+ _X_
67
+ ___
68
+ ___
69
+ END
70
+
71
+ STAR = <<-'END'
72
+ _X_
73
+ XXX
74
+ _X_
75
+ END
76
+
77
+ HASH = <<-'END'
78
+ XXX
79
+ XXX
80
+ XXX
81
+ END
82
+
83
+ def initialize(context)
84
+ @context = context
85
+ @char_width = 3
86
+ @char_height = 3
87
+ @mapping = {
88
+ " " => create_pattern(SPACE),
89
+ "/" => create_pattern(SLASH),
90
+ "\\" => create_pattern(BACKSLASH),
91
+ "`" => create_pattern(BACKTICK),
92
+ "|" => create_pattern(PIPE),
93
+ "-" => create_pattern(MINUS),
94
+ "_" => create_pattern(UNDERSCORE),
95
+ "." => create_pattern(FULLSTOP),
96
+ "\"" => create_pattern(DOUBLEQUOTES),
97
+ "'" => create_pattern(SINGLEQUOTE),
98
+ "*" => create_pattern(STAR),
99
+ "\#" => create_pattern(HASH),
100
+ }
101
+ end
102
+
103
+ def create_data(pattern)
104
+ a = pattern.split("\n")
105
+ fail "pattern has wrong height" if a.size != char_height
106
+ char_height.times do |dy|
107
+ fail "pattern has wrong width" if a[dy].size != char_width
108
+ end
109
+ a
110
+ end
111
+
112
+ def create_pattern(pattern)
113
+ char = TextDotter.new(char_width, char_height)
114
+ a = create_data(pattern)
115
+ char_height.times do |y|
116
+ char_width.times do |x|
117
+ char.dot(x, y) if a[y][x] == "X"
118
+ end
119
+ end
120
+ char
121
+ end
122
+
123
+ def get_pattern(x, y)
124
+ pattern = ""
125
+ char_height.times do |dy|
126
+ char_width.times do |dx|
127
+ if context.in?(x + dx, y + dy)
128
+ pattern += (context.dot?(x + dx, y + dy) ? "X" : "_")
129
+ else
130
+ pattern += "_"
131
+ end
132
+ end
133
+ pattern += "\n"
134
+ end
135
+ create_pattern(pattern.strip)
136
+ end
137
+
138
+ def difference(pattern1, pattern2)
139
+ m = 0
140
+ char_width.times do |dx|
141
+ char_height.times do |dy|
142
+ m += 1 if pattern1.dot?(dx, dy) != pattern2.dot?(dx, dy)
143
+ end
144
+ end
145
+ m
146
+ end
147
+
148
+ def get_matching(pattern)
149
+ ranking = {}
150
+ mapping.each do |k, v|
151
+ r = difference(pattern, v)
152
+ ranking[k] = r
153
+ end
154
+ ranking.min_by{|k, v| v}[0]
155
+ end
156
+
157
+
158
+ def ascii
159
+ a = ""
160
+ (context.height / char_height).times do |y|
161
+ (context.width / char_width).times do |x|
162
+ a += get_matching(get_pattern(x * char_width, y * char_height))
163
+ end
164
+ a += "\n"
165
+ end
166
+ a.chomp
167
+ end
168
+ end
169
+ end
170
+ end