vamp 0.1.3 → 0.1.4
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +20 -3
- data/lib/vamp/art.rb +189 -0
- data/lib/vamp/graphic/context.rb +142 -0
- data/lib/vamp/graphic/dotter.rb +53 -0
- data/lib/vamp/graphic/text_dotter.rb +35 -0
- data/lib/vamp/graphic/transfer.rb +170 -0
- data/lib/vamp/graphic/transfer5.rb +217 -0
- data/lib/vamp/graphic.rb +17 -0
- data/lib/vamp/version.rb +1 -1
- data/lib/vamp.rb +5 -12
- data/sample/gui.rb +98 -0
- data/spec/art_spec.rb +56 -0
- data/spec/graphic/context_spec.rb +364 -0
- data/spec/graphic/transfer5_spec.rb +179 -0
- data/spec/graphic/transfer_spec.rb +221 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/vamp_spec.rb +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c4315d0432b085681e7afa71522bfc0fe3e04f3
|
4
|
+
data.tar.gz: 591b310d5939ddfa3070a867b54f8c603092e72f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16383a97ea438b01e28dc035290fc1d5ed58952f516a70df23a702088a2d323c138b475e5dd91a5e7653ba57b6d57d241e49ceac634e794f9f651a2df48868b2
|
7
|
+
data.tar.gz: f831bae4c7f817ac9fc073fdefd45ff0f8a5dd48bc868709c0cb4a634d4ee91e37ce0b141ba1ab3dc10ba8f1ada633aca1f6e173db5ced106dfcbabaa51f3614
|
data/.gitignore
CHANGED
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
|
+
[](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
|
+
[1;33;48m , _.._ ,
|
21
|
+
(`._."` `"._.')
|
22
|
+
'._ _.' /\
|
23
|
+
| /`-. .-'\ | __ .'.'
|
24
|
+
|(_[1;32;48m()[1;33;48m_\/_[1;32;48m()[1;33;48m_)|' `\ ( (
|
25
|
+
; ,____, ; \ ) )
|
26
|
+
\ /[1;37;48mVvvV[1;33;48m\ / \ \.__ / /
|
27
|
+
/`'._`""`_.' \ \ `\/ /
|
28
|
+
/ . `--' \ \ /
|
29
|
+
/ / `-, _.----' \ ;
|
30
|
+
/ / ) / .--------` \
|
31
|
+
/ /.----' / / ___. \
|
32
|
+
/ /| _ _,| (---' \ |
|
33
|
+
/ / | \`""` \\\\ \ |
|
34
|
+
/ /` | | \\\` \ \
|
35
|
+
/ / [1;34;48m;[1;33;48m [1;34;48m|[1;33;48m / /
|
36
|
+
/ / [1;34;48m_[1;33;48m [1;34;48m\[1;33;48m [1;34;48m/[1;33;48m [1;34;48m/`[1;33;48m [1;34;48m/`[1;33;48m
|
37
|
+
/ _\[1;34;48m/([1;33;48m [1;34;48m|[1;33;48m [1;34;48m|[1;33;48m [1;34;48m/[1;33;48m [1;34;48m.'_[1;33;48m
|
38
|
+
| ( \ [1;34;48m'--'[1;33;48m [1;34;48m\[1;33;48m [1;34;48m.'[1;33;48m [1;34;48m(__)`\[1;33;48m
|
39
|
+
\\\\ [1;34;48m`-------'[1;33;48m [1;30;48mjgs[1;33;48m [1;34;48m/________.'[1;33;48m
|
40
|
+
`\\\
|
41
|
+
[0m
|
42
|
+
END
|
43
|
+
HOBGOBLIN = remove_ansi(HOBGOBLIN_COLOR)
|
44
|
+
SHARK_COLOR = <<-'END'
|
45
|
+
[1;36;48m [1;32;48mo[0;37;48m
|
46
|
+
[1;36;48m ___.. ,[0;37;48m
|
47
|
+
[1;36;48m __..--''__ ( .';[0;37;48m
|
48
|
+
[1;36;48m [1;32;48mo[1;36;48m __.-------.-' `--..__ .' ;[0;37;48m
|
49
|
+
[1;36;48m _.--' [1;35;48m0[1;36;48m) .--._ ``--...____.' .'[0;37;48m
|
50
|
+
[1;36;48m ( _. )). .__.-'' <[0;37;48m
|
51
|
+
[1;36;48m ```[0;37;48m``[1;36;48m---....._____.....- -..___ _____...--'-.'.[0;37;48m
|
52
|
+
[1;36;48m [1;30;48mjgs[1;36;48m `-.___.' ``````` `.;[0;37;48m
|
53
|
+
[0m
|
54
|
+
END
|
55
|
+
SHARK = remove_ansi(SHARK_COLOR)
|
56
|
+
DRAGON_COLOR = <<-'END'
|
57
|
+
[0;37;48m [1;32;48m ___ ___[0;37;48m
|
58
|
+
[1;32;48m ,_;-'-._\__/_.-'[0;37;48m
|
59
|
+
[1;32;48m ,_\ [1;31;48ma[1;32;48m\/[1;31;48ma[0;37;48m
|
60
|
+
[1;32;48m ,_\ ,-( _'-._
|
61
|
+
,_\ ([0;37;48m==[1;32;48m/\ |'-._\[0;37;48m
|
62
|
+
[1;32;48m ,_\ -. /\ \/ | |\ `[0;37;48m
|
63
|
+
[1;32;48m ,_\ \/[0;37;48m==[1;32;48m\ '._\7 '._
|
64
|
+
[0;32;48mjgs[1;32;48m '. '._ \[0;37;48m=[1;32;48m/\'-}}} '-}}}[0;37;48m
|
65
|
+
[1;32;48m / /> /` )
|
66
|
+
|\_.' .'( <_ <_
|
67
|
+
\____.-' '--}}}-}}}[0;37;48m
|
68
|
+
[0m
|
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
|
+
[1;31;48m _,.-------.,_
|
76
|
+
,;~' '~;,
|
77
|
+
,; ;,
|
78
|
+
; ;
|
79
|
+
,' ',
|
80
|
+
,; ;,
|
81
|
+
; ; . . ; ;
|
82
|
+
| ; ______ ______ ; |
|
83
|
+
| `/~" ~" . "~ "~\' |
|
84
|
+
| ~ ,-~~~^~, | ,~^~~~-, ~ |
|
85
|
+
| | }:{ | |
|
86
|
+
| l / | \ ! |
|
87
|
+
.~ (__,.--" .^. "--.,__) ~.
|
88
|
+
| ---;' / | \ `;--- |
|
89
|
+
\__. \/^\/ .__/
|
90
|
+
V| \ / |V
|
91
|
+
| |T~\___!___!___/~T| |
|
92
|
+
| |`[1;37;48mIIII_I_I_I_IIII'[1;31;48m| |
|
93
|
+
| \,[1;37;48mIII I I I III[1;31;48m,/ |
|
94
|
+
\ `~~~~~~~~~~' /
|
95
|
+
\ . . / [1;30;48m-dcau[1;31;48m
|
96
|
+
\. ^ ./
|
97
|
+
^~~~^~~~^
|
98
|
+
[0m
|
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
|
+
[0;37;48m [1;32;48m)/_[0;37;48m
|
106
|
+
[1;32;48m_.--..---"-,--[1;34;48mc[1;32;48m_[0;37;48m
|
107
|
+
[1;32;48m\L..'[0;37;48m [1;32;48m._[1;34;48mO[1;32;48m__)[1;31;48m_[0;37;48m
|
108
|
+
[1;32;48m,-.[0;37;48m [1;32;48m_.+[0;37;48m [1;32;48m_[0;37;48m [1;32;48m\..--( /[0;37;48m [0;35;48ma:f[0;37;48m
|
109
|
+
[1;32;48m`\.-''__.-'[0;37;48m [1;32;48m\ ([0;37;48m [1;32;48m\_[0;37;48m
|
110
|
+
[1;32;48m`'''[0;37;48m [1;32;48m`\__[0;37;48m [1;32;48m/\[0;37;48m
|
111
|
+
[1;32;48m')[0;37;48m
|
112
|
+
[0m
|
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
|