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