rubyzip 0.9.1 → 2.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +354 -0
- data/Rakefile +15 -104
- data/TODO +0 -1
- data/lib/zip/central_directory.rb +212 -0
- data/lib/zip/compressor.rb +9 -0
- data/lib/zip/constants.rb +115 -0
- data/lib/zip/crypto/decrypted_io.rb +40 -0
- data/lib/zip/crypto/encryption.rb +11 -0
- data/lib/zip/crypto/null_encryption.rb +43 -0
- data/lib/zip/crypto/traditional_encryption.rb +99 -0
- data/lib/zip/decompressor.rb +31 -0
- data/lib/zip/deflater.rb +34 -0
- data/lib/zip/dos_time.rb +53 -0
- data/lib/zip/entry.rb +719 -0
- data/lib/zip/entry_set.rb +88 -0
- data/lib/zip/errors.rb +19 -0
- data/lib/zip/extra_field/generic.rb +44 -0
- data/lib/zip/extra_field/ntfs.rb +94 -0
- data/lib/zip/extra_field/old_unix.rb +46 -0
- data/lib/zip/extra_field/universal_time.rb +77 -0
- data/lib/zip/extra_field/unix.rb +39 -0
- data/lib/zip/extra_field/zip64.rb +70 -0
- data/lib/zip/extra_field/zip64_placeholder.rb +15 -0
- data/lib/zip/extra_field.rb +103 -0
- data/lib/zip/file.rb +468 -0
- data/lib/zip/filesystem.rb +643 -0
- data/lib/zip/inflater.rb +54 -0
- data/lib/zip/input_stream.rb +180 -0
- data/lib/zip/ioextras/abstract_input_stream.rb +122 -0
- data/lib/zip/ioextras/abstract_output_stream.rb +43 -0
- data/lib/zip/ioextras.rb +21 -140
- data/lib/zip/null_compressor.rb +15 -0
- data/lib/zip/null_decompressor.rb +19 -0
- data/lib/zip/null_input_stream.rb +10 -0
- data/lib/zip/output_stream.rb +198 -0
- data/lib/zip/pass_thru_compressor.rb +23 -0
- data/lib/zip/pass_thru_decompressor.rb +31 -0
- data/lib/zip/streamable_directory.rb +15 -0
- data/lib/zip/streamable_stream.rb +52 -0
- data/lib/zip/version.rb +3 -0
- data/lib/zip.rb +72 -0
- data/samples/example.rb +44 -32
- data/samples/example_filesystem.rb +16 -19
- data/samples/example_recursive.rb +54 -0
- data/samples/gtk_ruby_zip.rb +84 -0
- data/samples/qtzip.rb +25 -34
- data/samples/write_simple.rb +10 -13
- data/samples/zipfind.rb +38 -45
- metadata +182 -91
- data/ChangeLog +0 -1504
- data/NEWS +0 -144
- data/README +0 -72
- data/install.rb +0 -22
- data/lib/download_quizzes.rb +0 -119
- data/lib/quiz1/t/solutions/Bill Guindon/solitaire.rb +0 -205
- data/lib/quiz1/t/solutions/Carlos/solitaire.rb +0 -111
- data/lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb +0 -111
- data/lib/quiz1/t/solutions/Florian Gross/solitaire.rb +0 -301
- data/lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb +0 -268
- data/lib/quiz1/t/solutions/James Edward Gray II/solitaire.rb +0 -132
- data/lib/quiz1/t/solutions/Jamis Buck/bin/main.rb +0 -13
- data/lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb +0 -230
- data/lib/quiz1/t/solutions/Jamis Buck/lib/cli.rb +0 -24
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_deck.rb +0 -30
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_key-stream.rb +0 -19
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_keying-algorithms.rb +0 -31
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_solitaire-cipher.rb +0 -66
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_unkeyed-algorithm.rb +0 -17
- data/lib/quiz1/t/solutions/Jamis Buck/test/tests.rb +0 -2
- data/lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb +0 -204
- data/lib/quiz1/t/solutions/Jim Menard/test.rb +0 -47
- data/lib/quiz1/t/solutions/Moses Hohman/cipher.rb +0 -97
- data/lib/quiz1/t/solutions/Moses Hohman/deck.rb +0 -140
- data/lib/quiz1/t/solutions/Moses Hohman/solitaire.rb +0 -14
- data/lib/quiz1/t/solutions/Moses Hohman/test_cipher.rb +0 -68
- data/lib/quiz1/t/solutions/Moses Hohman/test_deck.rb +0 -146
- data/lib/quiz1/t/solutions/Moses Hohman/test_util.rb +0 -38
- data/lib/quiz1/t/solutions/Moses Hohman/testsuite.rb +0 -5
- data/lib/quiz1/t/solutions/Moses Hohman/util.rb +0 -27
- data/lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb +0 -151
- data/lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb +0 -198
- data/lib/zip/stdrubyext.rb +0 -111
- data/lib/zip/tempfile_bugfixed.rb +0 -195
- data/lib/zip/zip.rb +0 -1847
- data/lib/zip/zipfilesystem.rb +0 -609
- data/lib/zip/ziprequire.rb +0 -90
- data/samples/gtkRubyzip.rb +0 -86
- data/test/alltests.rb +0 -9
- data/test/data/file1.txt +0 -46
- data/test/data/file1.txt.deflatedData +0 -0
- data/test/data/file2.txt +0 -1504
- data/test/data/notzippedruby.rb +0 -7
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/testDirectory.bin +0 -0
- data/test/data/zipWithDirs.zip +0 -0
- data/test/gentestfiles.rb +0 -157
- data/test/ioextrastest.rb +0 -208
- data/test/stdrubyexttest.rb +0 -52
- data/test/zipfilesystemtest.rb +0 -831
- data/test/ziprequiretest.rb +0 -43
- data/test/ziptest.rb +0 -1599
@@ -1,204 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
RANKS = %w(A 2 3 4 5 6 7 8 9 10 J Q K)
|
4
|
-
SUITS = %w(C D H S)
|
5
|
-
JOKER_RANK = 'joker'
|
6
|
-
JOKER_VALUE = -1
|
7
|
-
|
8
|
-
class Card
|
9
|
-
def Card.value_to_chr(value)
|
10
|
-
i = value
|
11
|
-
i -= 26 while i > 26
|
12
|
-
(i + ?A - 1).chr
|
13
|
-
end
|
14
|
-
def Card.chr_to_value(chr)
|
15
|
-
i = chr[0] - ?A + 1
|
16
|
-
i += 26 while i < 0
|
17
|
-
i
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize(rank, suit)
|
21
|
-
@rank = rank
|
22
|
-
@suit = suit
|
23
|
-
if rank == JOKER_RANK
|
24
|
-
@value = JOKER_VALUE
|
25
|
-
else
|
26
|
-
@value = (SUITS.index(suit) * 13) + RANKS.index(rank) + 1
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_s
|
31
|
-
# return @value.to_s if @value != JOKER_VALUE
|
32
|
-
# return @suit.to_s
|
33
|
-
"#{@rank}#{@suit} #{@value.to_s}"
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_i
|
37
|
-
@value
|
38
|
-
end
|
39
|
-
|
40
|
-
def chr
|
41
|
-
Card.value_to_chr(@value)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
class Deck
|
46
|
-
|
47
|
-
def initialize
|
48
|
-
@cards = []
|
49
|
-
SUITS.each { | suit |
|
50
|
-
RANKS.each { | rank | @cards << Card.new(rank, suit) }
|
51
|
-
}
|
52
|
-
@joker_a = Card.new(JOKER_RANK, 'A')
|
53
|
-
@cards << @joker_a
|
54
|
-
@joker_b = Card.new(JOKER_RANK, 'B')
|
55
|
-
@cards << @joker_b
|
56
|
-
end
|
57
|
-
|
58
|
-
# Keys the deck and returns itself.
|
59
|
-
def key
|
60
|
-
# do nothing; keyed when initialized
|
61
|
-
self
|
62
|
-
end
|
63
|
-
|
64
|
-
# Return the next kestream value as a number (not a string).
|
65
|
-
# Keep going until we have a non-joker value.
|
66
|
-
def next_keystream
|
67
|
-
val = JOKER_VALUE
|
68
|
-
until val != JOKER_VALUE
|
69
|
-
val = generate_next_keystream_value
|
70
|
-
end
|
71
|
-
val
|
72
|
-
end
|
73
|
-
|
74
|
-
# Return the next keystream value as a number 1-26 (not a string).
|
75
|
-
def generate_next_keystream_value
|
76
|
-
move(@joker_a, 1)
|
77
|
-
move(@joker_b, 2)
|
78
|
-
triple_cut()
|
79
|
-
count_cut()
|
80
|
-
return output_number()
|
81
|
-
end
|
82
|
-
|
83
|
-
# Move a card a certain distance. Wrap around the end of the deck.
|
84
|
-
def move(card, distance)
|
85
|
-
old_pos = @cards.index(card)
|
86
|
-
new_pos = old_pos + distance
|
87
|
-
new_pos -= (@cards.length-1) if new_pos >= @cards.length
|
88
|
-
@cards[old_pos,1] = []
|
89
|
-
@cards[new_pos,0] = [card]
|
90
|
-
end
|
91
|
-
|
92
|
-
# Perform a triple cut around the two jokers. All cards above the top
|
93
|
-
# joker move to below the bottom joker and vice versa. The jokers and the
|
94
|
-
# cards between them do not move.
|
95
|
-
def triple_cut
|
96
|
-
i = @cards.index(@joker_a)
|
97
|
-
j = @cards.index(@joker_b)
|
98
|
-
j, i = i, j if j < i # make sure i < j
|
99
|
-
@cards = slice(j+1, -1) + slice(i, j) + slice(0, i-1)
|
100
|
-
end
|
101
|
-
|
102
|
-
# Perform a count cut using the value of the bottom card. Cut the bottom
|
103
|
-
# card's value in cards off the top of the deck and reinsert them just
|
104
|
-
# above the bottom card.
|
105
|
-
def count_cut
|
106
|
-
i = @cards[@cards.length - 1].to_i
|
107
|
-
@cards = slice(i, -2) + slice(0, i-1) + [@cards[@cards.length-1]]
|
108
|
-
end
|
109
|
-
|
110
|
-
# Returns a non-nil cut of cards from the deck.
|
111
|
-
def slice(from, to)
|
112
|
-
slice = @cards[from..to]
|
113
|
-
return slice || []
|
114
|
-
end
|
115
|
-
|
116
|
-
# Return the output number (not letter). Convert the top card to it's
|
117
|
-
# value and count down that many cards from the top of the deck, with the
|
118
|
-
# top card itself being card number one. Look at the card immediately
|
119
|
-
# after your count and convert it to a letter. This is the next letter in
|
120
|
-
# the keystream. If the output card is a joker, no letter is generated
|
121
|
-
# this sequence. This step does not alter the deck.
|
122
|
-
def output_number
|
123
|
-
i = @cards[0].to_i
|
124
|
-
i -= @cards.length if i >= @cards.length
|
125
|
-
num = @cards[i].to_i
|
126
|
-
num -= 26 if num > 26
|
127
|
-
num
|
128
|
-
end
|
129
|
-
|
130
|
-
def to_s
|
131
|
-
@cards.join(' ')
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
class CryptKeeper
|
136
|
-
|
137
|
-
def initialize(deck)
|
138
|
-
@keyed_deck = deck
|
139
|
-
end
|
140
|
-
|
141
|
-
def decrypt(str)
|
142
|
-
@deck = @keyed_deck.dup
|
143
|
-
answer = ""
|
144
|
-
str.split(//).each { | c |
|
145
|
-
if c == ' '
|
146
|
-
answer << ' '
|
147
|
-
next
|
148
|
-
end
|
149
|
-
|
150
|
-
msg_num = Card.chr_to_value(c)
|
151
|
-
key = @deck.next_keystream
|
152
|
-
diff = msg_num - key
|
153
|
-
diff += 26 if diff < 1
|
154
|
-
answer << Card.value_to_chr(diff)
|
155
|
-
}
|
156
|
-
answer
|
157
|
-
end
|
158
|
-
|
159
|
-
def encrypt(str)
|
160
|
-
@deck = @keyed_deck.dup
|
161
|
-
answer = ''
|
162
|
-
str.split(//).each { | c |
|
163
|
-
if c == ' '
|
164
|
-
answer << ' '
|
165
|
-
next
|
166
|
-
end
|
167
|
-
|
168
|
-
msg_num = Card.chr_to_value(c)
|
169
|
-
key = @deck.next_keystream
|
170
|
-
sum = msg_num + key
|
171
|
-
sum -= 26 if sum > 26
|
172
|
-
answer << Card.value_to_chr(sum)
|
173
|
-
}
|
174
|
-
answer
|
175
|
-
end
|
176
|
-
|
177
|
-
def crypto_each(str)
|
178
|
-
@deck = @keyed_deck.dup
|
179
|
-
str.split(//).each { | c | yield c }
|
180
|
-
end
|
181
|
-
|
182
|
-
end
|
183
|
-
|
184
|
-
def prep_arg(str)
|
185
|
-
str = str.upcase.gsub(/[^A-Z]/, '')
|
186
|
-
words = []
|
187
|
-
while str.length > 0
|
188
|
-
words << str[0...5]
|
189
|
-
str[0...5] = ''
|
190
|
-
end
|
191
|
-
|
192
|
-
last_len = words[words.length-1].length
|
193
|
-
words[words.length-1] += ('X' * (5 - last_len)) if last_len < 5
|
194
|
-
words.join(' ')
|
195
|
-
end
|
196
|
-
|
197
|
-
if __FILE__ == $0
|
198
|
-
if ARGV[0]
|
199
|
-
puts CryptKeeper.new(Deck.new.key).decrypt(prep_arg(ARGV[0]))
|
200
|
-
else
|
201
|
-
puts CryptKeeper.new(Deck.new.key).decrypt('CLEPK HHNIY CFPWH FDFEH')
|
202
|
-
puts CryptKeeper.new(Deck.new.key).decrypt('ABVAW LWZSY OORYK DUPVH')
|
203
|
-
end
|
204
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'test/unit.rb'
|
4
|
-
require 'test/unit/ui/console/testrunner'
|
5
|
-
require 'solitaire_cypher.rb'
|
6
|
-
|
7
|
-
class SolitaireCypherTest < Test::Unit::TestCase
|
8
|
-
|
9
|
-
KNOWN_PLAINTEXT = 'CODEI NRUBY LIVEL ONGER'
|
10
|
-
KNOWN_CYPHER = 'GLNCQ MJAFF FVOMB JIYCB'
|
11
|
-
|
12
|
-
def setup
|
13
|
-
@deck = Deck.new.key
|
14
|
-
@crypt_keeper = CryptKeeper.new(@deck)
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_value_to_chr
|
18
|
-
assert_equal('A', Card.value_to_chr(1))
|
19
|
-
assert_equal('Z', Card.value_to_chr(26))
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_chr_to_value
|
23
|
-
assert_equal(1, Card.chr_to_value("A"))
|
24
|
-
assert_equal(26, Card.chr_to_value("Z"))
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_keystream
|
28
|
-
expected = %w(D W J X H Y R F D G)
|
29
|
-
deck = Deck.new.key
|
30
|
-
expected.each { | exp |
|
31
|
-
key = deck.next_keystream
|
32
|
-
if exp != Card.value_to_chr(key)
|
33
|
-
@errors << "expected #{exp}, key = #{Card.value_to_chr(key)}"
|
34
|
-
end
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_decrypt_known_cypher
|
39
|
-
assert_equal(KNOWN_PLAINTEXT, @crypt_keeper.decrypt(KNOWN_CYPHER))
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_encrypt_known_message
|
43
|
-
assert_equal(KNOWN_CYPHER, @crypt_keeper.encrypt(KNOWN_PLAINTEXT))
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
Test::Unit::UI::Console::TestRunner.run(SolitaireCypherTest)
|
@@ -1,97 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'util'
|
3
|
-
require 'deck'
|
4
|
-
|
5
|
-
module Solitaire
|
6
|
-
ASCII_OFFSET = 64
|
7
|
-
ALPHABET_SIZE = 26
|
8
|
-
|
9
|
-
class Chunker
|
10
|
-
CHUNK_SIZE = 5
|
11
|
-
|
12
|
-
def initialize(text)
|
13
|
-
@legal_chars_only = text.gsub(/[^A-Za-z]/, "").upcase
|
14
|
-
@legal_chars_only <<= "X" * (-@legal_chars_only.size % CHUNK_SIZE)
|
15
|
-
raise "Nothing to chunk (non-alphabet characters removed): #{text}" if @legal_chars_only.size==0
|
16
|
-
@chunks = []
|
17
|
-
@number_chunks = []
|
18
|
-
end
|
19
|
-
|
20
|
-
def chunks
|
21
|
-
@chunks if @chunks.size > 0
|
22
|
-
@chunks = @legal_chars_only.gsub(/(.{#{CHUNK_SIZE}})/, '\1 ').rstrip.split(" ")
|
23
|
-
end
|
24
|
-
|
25
|
-
def number_chunks
|
26
|
-
@number_chunks if @number_chunks.size > 0
|
27
|
-
chunks.collect { |chunk| chunk.split("").collect { |char_string| char_string[0]-ASCII_OFFSET } }
|
28
|
-
end
|
29
|
-
|
30
|
-
def Chunker.to_letters(number_chunks)
|
31
|
-
number_chunks.collect { |chunk| chunk.collect { |num| (num+ASCII_OFFSET).chr }.join }
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class Keystream
|
36
|
-
A_JOKER = Card.joker(?A)
|
37
|
-
B_JOKER = Card.joker(?B)
|
38
|
-
|
39
|
-
def initialize(deck=Deck.new)
|
40
|
-
@deck = deck
|
41
|
-
end
|
42
|
-
|
43
|
-
def keystream_letters(chunks)
|
44
|
-
chunks.collect { |chunk| (1..chunk.size).collect { next_keystream_letter }.join }
|
45
|
-
end
|
46
|
-
|
47
|
-
def Keystream.card_to_letter(card)
|
48
|
-
return "" if card.is_joker?
|
49
|
-
(card.value.offset_mod(ALPHABET_SIZE)+ASCII_OFFSET).chr
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def next_keystream_letter
|
55
|
-
process_deck
|
56
|
-
top_card = @deck[0]
|
57
|
-
keystream_card = @deck[top_card.value]
|
58
|
-
letter = Keystream.card_to_letter(keystream_card)
|
59
|
-
letter = next_keystream_letter if letter==""
|
60
|
-
letter
|
61
|
-
end
|
62
|
-
|
63
|
-
def process_deck
|
64
|
-
@deck.move_card!(A_JOKER, +1)
|
65
|
-
@deck.move_card!(B_JOKER, +2)
|
66
|
-
@deck.triple_cut!([A_JOKER, B_JOKER])
|
67
|
-
@deck.count_cut!
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
class Cipher
|
72
|
-
ENCRYPTED_TEXT_PATTERN = /\A[A-Z]{5}( [A-Z]{5})*\Z/
|
73
|
-
|
74
|
-
def initialize(text, deck=Deck.new)
|
75
|
-
@chunker = Chunker.new(text)
|
76
|
-
keystream = Keystream.new(deck)
|
77
|
-
@keystream_chunker = Chunker.new(keystream.keystream_letters(@chunker.chunks).join)
|
78
|
-
if text =~ ENCRYPTED_TEXT_PATTERN
|
79
|
-
@mode = "decrypt"
|
80
|
-
@calc_number = proc { |num, keystream_num| num - keystream_num }
|
81
|
-
else
|
82
|
-
@mode = "encrypt"
|
83
|
-
@calc_number = proc { |num, keystream_num| num + keystream_num }
|
84
|
-
end
|
85
|
-
end
|
86
|
-
attr_reader :mode
|
87
|
-
|
88
|
-
def crypt
|
89
|
-
ciphered = [@chunker.number_chunks, @keystream_chunker.number_chunks].collect_peel do |num_chunk, keystream_num_chunk|
|
90
|
-
[num_chunk, keystream_num_chunk].collect_peel do |num, keystream_num|
|
91
|
-
@calc_number.call(num,keystream_num).offset_mod(ALPHABET_SIZE)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
Chunker.to_letters(ciphered).join(" ").rstrip
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
@@ -1,140 +0,0 @@
|
|
1
|
-
require 'util'
|
2
|
-
|
3
|
-
module Solitaire
|
4
|
-
class Deck
|
5
|
-
NUM_CARDS = 54
|
6
|
-
|
7
|
-
def initialize(order=nil)
|
8
|
-
if order.nil?
|
9
|
-
@order = Array.new(NUM_CARDS) { |x| x+1 }
|
10
|
-
else
|
11
|
-
@order = order.collect { |val| val.instance_of?(Range) ? val.to_a : val }.flatten
|
12
|
-
@order.collect! { |val| Card.parse(val).code }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
attr_reader :order
|
16
|
-
protected :order
|
17
|
-
|
18
|
-
def [](index)
|
19
|
-
Card.parse(@order[index])
|
20
|
-
end
|
21
|
-
|
22
|
-
def move_card!(card, offset)
|
23
|
-
current_index = @order.index(card.code)
|
24
|
-
new_index = current_index+offset
|
25
|
-
if new_index >= NUM_CARDS
|
26
|
-
new_index -= NUM_CARDS - 1
|
27
|
-
elsif new_index < 0
|
28
|
-
new_index += NUM_CARDS - 1
|
29
|
-
end
|
30
|
-
@order.delete_at(current_index)
|
31
|
-
@order.insert(new_index, card.code)
|
32
|
-
end
|
33
|
-
|
34
|
-
def triple_cut!(cards)
|
35
|
-
raise "exactly two cards required for triple cut: #{cards}" unless cards.size==2
|
36
|
-
indices = [@order.index(cards[0].code), @order.index(cards[1].code)].sort
|
37
|
-
@order = @order[(indices[1]+1)..@order.size] + @order[indices[0]..indices[1]] + @order[0..(indices[0]-1)]
|
38
|
-
end
|
39
|
-
|
40
|
-
def count_cut!
|
41
|
-
num_moved = Card.parse(@order.last).value
|
42
|
-
if num_moved!=53
|
43
|
-
@order = @order[num_moved, NUM_CARDS - num_moved - 1] + @order[0..(num_moved-1)] + [@order.last]
|
44
|
-
end
|
45
|
-
self
|
46
|
-
end
|
47
|
-
|
48
|
-
def to_s
|
49
|
-
"<Deck: #{@order.inspect}>"
|
50
|
-
end
|
51
|
-
|
52
|
-
def ==(val)
|
53
|
-
@order == val.order
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
class Card
|
58
|
-
ACE = 1
|
59
|
-
JACK = 11
|
60
|
-
QUEEN = 12
|
61
|
-
KING = 13
|
62
|
-
|
63
|
-
def initialize(suit, value)
|
64
|
-
@code = suit.value + value
|
65
|
-
end
|
66
|
-
attr_reader :code
|
67
|
-
alias_method :value, :code
|
68
|
-
|
69
|
-
def Card.parse(code)
|
70
|
-
if (1..52).member?(code)
|
71
|
-
Card.new(Suit.by_value(code), code.offset_mod(13))
|
72
|
-
elsif (53..54).member?(code)
|
73
|
-
Card.joker(code+12)
|
74
|
-
elsif (65..66).member?(code)
|
75
|
-
Card.joker(code)
|
76
|
-
elsif code =~ /\A[AB]\Z/
|
77
|
-
Card.joker(code[0])
|
78
|
-
else
|
79
|
-
raise "Illegal class or value for parameter value, #{code.class} #{code.inspect}"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def Card.joker(char)
|
84
|
-
JokerCard.new(char.chr)
|
85
|
-
end
|
86
|
-
|
87
|
-
def is_joker?
|
88
|
-
false
|
89
|
-
end
|
90
|
-
|
91
|
-
def ==(other)
|
92
|
-
code==other.code
|
93
|
-
end
|
94
|
-
|
95
|
-
def <=>(other)
|
96
|
-
code<=>other.code
|
97
|
-
end
|
98
|
-
|
99
|
-
def to_s
|
100
|
-
"Card: #{@code}"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
class JokerCard < Card
|
105
|
-
JOKER_VALUE = 53
|
106
|
-
|
107
|
-
def initialize(which_one)
|
108
|
-
raise "No such joker: #{which_one}" unless which_one =~ /\A[AB]\Z/
|
109
|
-
@code = 52 + (which_one[0].to_i-64)
|
110
|
-
end
|
111
|
-
|
112
|
-
def is_joker?
|
113
|
-
true
|
114
|
-
end
|
115
|
-
|
116
|
-
def value
|
117
|
-
JOKER_VALUE
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
class Suit
|
122
|
-
@@byValue = {}
|
123
|
-
|
124
|
-
def Suit.by_value(val)
|
125
|
-
@@byValue[(val-1)/13*13]
|
126
|
-
end
|
127
|
-
|
128
|
-
def initialize(name, value)
|
129
|
-
@name = name
|
130
|
-
@value = value
|
131
|
-
@@byValue[value] = self
|
132
|
-
end
|
133
|
-
attr_reader :name, :value
|
134
|
-
|
135
|
-
CLUBS = Suit.new("clubs", 0)
|
136
|
-
DIAMONDS = Suit.new("diamonds", 13)
|
137
|
-
HEARTS = Suit.new("hearts", 26)
|
138
|
-
SPADES = Suit.new("spades", 39)
|
139
|
-
end
|
140
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'cipher'
|
3
|
-
require 'yaml'
|
4
|
-
|
5
|
-
module Solitaire
|
6
|
-
text = ARGV.join(" ")
|
7
|
-
if FileTest::readable?("deck.yaml")
|
8
|
-
deck = Deck.new(YAML::load(File.open("deck.yaml")))
|
9
|
-
else
|
10
|
-
deck = Deck.new
|
11
|
-
end
|
12
|
-
cipher = Cipher.new(text, deck)
|
13
|
-
puts "#{cipher.mode}ed: #{cipher.crypt}"
|
14
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'test/unit'
|
3
|
-
require 'cipher'
|
4
|
-
|
5
|
-
module Solitaire
|
6
|
-
class TestChunker < Test::Unit::TestCase
|
7
|
-
def test_chunks
|
8
|
-
chunker = Chunker.new("Code in Ruby, live longer!")
|
9
|
-
assert_equal(["CODEI","NRUBY","LIVEL","ONGER"], chunker.chunks)
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_pads_with_Xs
|
13
|
-
chunker = Chunker.new("sty")
|
14
|
-
assert_equal(["STYXX"], chunker.chunks)
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_number_chunks
|
18
|
-
chunker = Chunker.new("Code in Ruby, live longer!")
|
19
|
-
assert_equal([[3,15,4,5,9], [14,18,21,2,25], [12,9,22,5,12], [15,14,7,5,18]], chunker.number_chunks)
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_to_letters
|
23
|
-
assert_equal(["CODEI","NRUBY","LIVEL","ONGER"],
|
24
|
-
Chunker.to_letters([[3,15,4,5,9], [14,18,21,2,25], [12,9,22,5,12], [15,14,7,5,18]]))
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class TestKeystream < Test::Unit::TestCase
|
29
|
-
def setup
|
30
|
-
@keystream = Keystream.new
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_keystream_letters
|
34
|
-
chunker = Chunker.new("Code in Ruby, live longer!")
|
35
|
-
assert_equal(["DWJXH","YRFDG","TMSHP","UURXJ"], @keystream.keystream_letters(chunker.chunks))
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_card_to_letter
|
39
|
-
assert_equal("", Keystream.card_to_letter(Card.joker(?A)), "A joker")
|
40
|
-
assert_equal("", Keystream.card_to_letter(Card.joker(?B)), "B joker")
|
41
|
-
assert_equal("A", Keystream.card_to_letter(Card.new(Suit::CLUBS, Card::ACE)), "AC")
|
42
|
-
assert_equal("Z", Keystream.card_to_letter(Card.new(Suit::DIAMONDS, Card::KING)), "KD")
|
43
|
-
assert_equal("A", Keystream.card_to_letter(Card.new(Suit::HEARTS, Card::ACE)), "AH")
|
44
|
-
assert_equal("Z", Keystream.card_to_letter(Card.new(Suit::SPADES, Card::KING)), "KS")
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
class TestCipher < Test::Unit::TestCase
|
49
|
-
def test_encrypt
|
50
|
-
cipher = Cipher.new("Code in Ruby, live longer!")
|
51
|
-
assert_equal("encrypt", cipher.mode)
|
52
|
-
assert_equal("GLNCQ MJAFF FVOMB JIYCB", cipher.crypt)
|
53
|
-
end
|
54
|
-
|
55
|
-
def test_decrypt
|
56
|
-
cipher = Cipher.new("GLNCQ MJAFF FVOMB JIYCB")
|
57
|
-
assert_equal("decrypt", cipher.mode)
|
58
|
-
assert_equal("CODEI NRUBY LIVEL ONGER", cipher.crypt)
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_crypt_idempotent
|
62
|
-
cipher = Cipher.new("GLNCQ MJAFF FVOMB JIYCB")
|
63
|
-
assert_equal("decrypt", cipher.mode)
|
64
|
-
assert_equal("CODEI NRUBY LIVEL ONGER", cipher.crypt)
|
65
|
-
assert_equal("CODEI NRUBY LIVEL ONGER", cipher.crypt)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,146 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'test/unit'
|
3
|
-
require 'deck'
|
4
|
-
|
5
|
-
module Solitaire
|
6
|
-
class TestDeck < Test::Unit::TestCase
|
7
|
-
def test_constructor_accepts_ranges_in_array
|
8
|
-
assert_equal(Deck.new, Deck.new([1, 2, 3, 4..52, 53..54]))
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_construcor_accepts_chars_for_jokers
|
12
|
-
assert_equal(Deck.new, Deck.new((1..52).to_a + [?A, ?B]))
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_move_card_lower
|
16
|
-
deck = Deck.new
|
17
|
-
deck.move_card!(Card.new(Suit::DIAMONDS, 6), +5)
|
18
|
-
assert_equal(Deck.new([1..18,20..24,19,25..54]).to_s, deck.to_s)
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_move_card_one_lower
|
22
|
-
deck = Deck.new
|
23
|
-
deck.move_card!(Card.new(Suit::DIAMONDS, 6), +1)
|
24
|
-
assert_equal(Deck.new([1..18,20,19,21..54]).to_s, deck.to_s)
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_move_card_higher
|
28
|
-
deck = Deck.new
|
29
|
-
deck.move_card!(Card.new(Suit::DIAMONDS, 6), -5)
|
30
|
-
assert_equal(Deck.new([1..13,19,14..18,20..54]), deck)
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_move_card_is_cyclic_plus_1
|
34
|
-
deck = Deck.new
|
35
|
-
deck.move_card!(Card.joker(?A), +2)
|
36
|
-
assert_equal(Deck.new([1,53,2..52,54]), deck)
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_move_card_to_end
|
40
|
-
deck = Deck.new
|
41
|
-
deck.move_card!(Card.joker(?A), +1)
|
42
|
-
assert_equal(Deck.new([1..52,54,53]), deck)
|
43
|
-
end
|
44
|
-
|
45
|
-
def test_move_card_to_one_before_end
|
46
|
-
deck = Deck.new([2..54,1])
|
47
|
-
deck.move_card!(Card.joker(?A), +1)
|
48
|
-
assert_equal(Deck.new([2..52,54,53,1]).to_s, deck.to_s)
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_move_card_to_beginning
|
52
|
-
deck = Deck.new
|
53
|
-
deck.move_card!(Card.new(Suit::CLUBS, 2), -1)
|
54
|
-
assert_equal(Deck.new([2,1,3..54]), deck)
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_move_card_is_cyclic_pass_end_forward
|
58
|
-
deck = Deck.new
|
59
|
-
deck.move_card!(Card.joker(?B), +1)
|
60
|
-
assert_equal(Deck.new([1,54,2..53]), deck)
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_move_card_is_cyclic_pass_end_backward
|
64
|
-
deck = Deck.new
|
65
|
-
deck.move_card!(Card.new(Suit::CLUBS, Card::ACE), -1)
|
66
|
-
assert_equal(Deck.new([2..53,1,54]), deck)
|
67
|
-
end
|
68
|
-
|
69
|
-
def test_move_card_cyclic_backward_five
|
70
|
-
deck = Deck.new
|
71
|
-
deck.move_card!(Card.new(Suit::CLUBS, 5), -5)
|
72
|
-
assert_equal(Deck.new([1..4,6..53,5,54]), deck)
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_triple_cut
|
76
|
-
deck = Deck.new
|
77
|
-
deck.triple_cut!([Card.new(Suit::CLUBS, Card::JACK), Card.new(Suit::HEARTS, Card::KING)])
|
78
|
-
assert_equal(Deck.new([40..54,11..39,1..10]), deck)
|
79
|
-
end
|
80
|
-
|
81
|
-
def test_triple_cut_with_empty_side
|
82
|
-
deck = Deck.new([2..53,1,54])
|
83
|
-
deck.triple_cut!([Card.joker(?A), Card.joker(?B)])
|
84
|
-
assert_equal(Deck.new([53,1,54,2..52]), deck)
|
85
|
-
end
|
86
|
-
|
87
|
-
def test_count_cut
|
88
|
-
deck = Deck.new
|
89
|
-
deck.move_card!(Card.new(Suit::CLUBS, 5), 49)
|
90
|
-
deck.count_cut!
|
91
|
-
assert_equal(Deck.new([7..54,1..4,6,5]), deck)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
class TestCard < Test::Unit::TestCase
|
96
|
-
def test_parse_joker_string
|
97
|
-
assert_equal(Card.joker(?A), Card.parse("A"))
|
98
|
-
end
|
99
|
-
|
100
|
-
def test_parse_joker_char
|
101
|
-
assert_equal(Card.joker(?A), Card.parse(?A))
|
102
|
-
end
|
103
|
-
|
104
|
-
def test_parse_normal_card
|
105
|
-
assert_equal(Card.new(Suit::CLUBS, 5), Card.parse(5))
|
106
|
-
end
|
107
|
-
|
108
|
-
def test_value
|
109
|
-
assert_equal(1, Card.new(Suit::CLUBS, Card::ACE).value, "AC")
|
110
|
-
assert_equal(7, Card.new(Suit::CLUBS, 7).value, "7C")
|
111
|
-
assert_equal(11, Card.new(Suit::CLUBS, Card::JACK).value, "JC")
|
112
|
-
assert_equal(13, Card.new(Suit::CLUBS, Card::KING).value, "KC")
|
113
|
-
assert_equal(14, Card.new(Suit::DIAMONDS, Card::ACE).value, "AD")
|
114
|
-
assert_equal(26, Card.new(Suit::DIAMONDS, Card::KING).value, "KD")
|
115
|
-
assert_equal(29, Card.new(Suit::HEARTS, 3).value, "3H")
|
116
|
-
assert_equal(39, Card.new(Suit::HEARTS, Card::KING).value, "KH")
|
117
|
-
assert_equal(40, Card.new(Suit::SPADES, Card::ACE).value, "AS")
|
118
|
-
assert_equal(52, Card.new(Suit::SPADES, Card::KING).value, "KS")
|
119
|
-
assert_equal(53, Card.joker(?A).value, "A Joker")
|
120
|
-
assert_equal(53, Card.joker(?B).value, "B Joker")
|
121
|
-
end
|
122
|
-
|
123
|
-
def test_is_joker_when_joker
|
124
|
-
assert(Card.joker(?A).is_joker?, "A joker not joker")
|
125
|
-
assert(Card.joker(?B).is_joker?, "B joker not joker")
|
126
|
-
end
|
127
|
-
|
128
|
-
def test_is_joker_when_not_joker
|
129
|
-
assert(!Card.new(Suit::SPADES, 7).is_joker?)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
class TestSuit < Test::Unit::TestCase
|
134
|
-
def test_by_value_clubs
|
135
|
-
assert_equal("clubs", Suit.by_value(1).name)
|
136
|
-
end
|
137
|
-
|
138
|
-
def test_by_value_hearts
|
139
|
-
assert_equal("hearts", Suit.by_value(27).name)
|
140
|
-
end
|
141
|
-
|
142
|
-
def test_hearts
|
143
|
-
assert_equal("hearts", Suit::HEARTS.name)
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|