Ruby squares II
This is a followup to Ruby squares, which I wrote way back in the first year of 2020. I promised a new Ruby golf program that would animate text in the terminal, hoping to release it “soon” (lol). One last bug kept me from releasing it. Now, so much time has passed that I can’t remember what that bug was, or whether I’d fixed it. So I’m releasing the code as it is, for the sake of closure.
Run the code in a terminal, and if all goes well (never a given), it’ll simulate the process of cracking a passphrase using the finest technology from Hollywood:
$ ruby passphrase.rb
>TS-IRCWPDZOUN GSOXIT DBAAI
>CHORIDKYMVZHDZOCZXYKT YZPS
>CHORISTIC D-QD-IMSOTYRJTPA
>CHORISTIC DIAGONAL TUVPXNA
>CHORISTIC DIAGONAL COATRBS
>CHORISTIC DIAGONAL COACTOR
passphrase.rb
Here’s the final code: three squares without spaces (except for comments).
#!/usr/bin/env ruby
Z=->a,*b{a.sample(*
b)};i=$stdin.tty?&&
File;f='/usr/share/
dict/words'.tr(?\n,
'')if(i);N=->s{$><<
s};w=(i||$<).read(f
).upcase.scan(/\b[^
E\s]+\b/x)-[p];E,T,
Q=->s{N["\e[?25"+s]
},Z[w,3]*?\s,(w*'')
.chars|[]+[?\s];i=0
R=->i{n=T.size-i;s=
(1..n).map{Z[Q]}*''
N[s];sleep(0.1/6);(
1-(s[0]<=>T[i])&1).
tap{|r|N[?\b.*n-r]}
};E[?l];begin;N[?>]
i+=R[i]until(!T[i])
ensure;E["h\n"];end
# ljc, 2020-11-12 #
Enhance! Enhance!
Here’s the “clean” version, which I developed side-by-side to help me keep track of things.
#!/usr/bin/env ruby
# frozen_string_literal: true
CSI_ESCAPE = "\e["
SHOW_CURSOR = "#{CSI_ESCAPE}?25h".freeze
HIDE_CURSOR = "#{CSI_ESCAPE}?25l".freeze
WORDS_FILE = '/usr/share/dict/words'
class Passphrase
def initialize
words = build_word_list
@chars = (words.join.chars + [' ']).uniq.freeze
@text = words.sample(3).join(' ')
end
def crack
print '>'
i = 0
while i < text.size
i += 1 if try_random_match?(i)
end
end
private
attr_reader :chars, :text
def build_word_list
read_words_file
.upcase
.split.uniq
.reject { |word| word.include?('E') }
end
def read_words_file
if $stdin.tty?
File.read(WORDS_FILE)
else
$stdin.read
end
end
def try_random_match?(i)
remaining = text.size - i
guess = remaining.times.map { chars.sample }.join
print guess
sleep(1.0 / 60)
match = guess[0] == text[i]
remaining -= 1 if match
print("\b" * remaining)
match
end
end
begin
print HIDE_CURSOR
Passphrase.new.crack
ensure
puts SHOW_CURSOR
end