class Shuffle

Constants

PREFIXES

Attributes

rejoin[R]
sequence[R]

Public Class Methods

new(sequence) click to toggle source
# File lib/shuffle.rb, line 13
def initialize(sequence)
  @sequence = if sequence.is_a?(String) && sequence !~ /\s/
    @rejoin = true
    sequence.split(//)
  else
    sequence
  end
end

Public Instance Methods

shuffle(size = 1) click to toggle source
# File lib/shuffle.rb, line 22
def shuffle(size = 1)
  shuffled_sequence = sequence.length > 1 ? shuffler(size) : sequence
  
  rejoin ? shuffled_sequence.join : shuffled_sequence
end
valid?(other_sequence, size) click to toggle source
# File lib/shuffle.rb, line 28
def valid?(other_sequence, size)
  split_other_sequence = other_sequence.is_a?(String) && sequence !~ /\s/ ? other_sequence.split(//) : other_sequence
  
  frequency(sequence.each_cons(size)) == frequency(split_other_sequence.each_cons(size))
end
validate_random(size) click to toggle source
# File lib/shuffle.rb, line 34
def validate_random(size)
  valid?(shuffler(size), size)
end

Private Instance Methods

connected?(edges, size) click to toggle source
# File lib/shuffle.rb, line 72
def connected?(edges, size)
  terminal          = terminal(size)
  vertex_terminates = edges.map { |edge| edge[0..-2] }.inject({}) { |hash, v| hash.tap { hash[v] = false } }
  queue             = edges.select { |edge| edge[1..-1] == terminal }

  until queue.empty?
    edge = queue.pop
    
    if vertex_terminates[edge[0..-2]] = vertex_terminates[edge[1..-1]] || edge[1..-1] == terminal
      queue.push(*edges.select { |queueable_edge| queueable_edge[1..-1] == edge[0..-2] })
    end
  end

  vertex_terminates.values.all?
end
construct_from(edge_hash, size) click to toggle source
# File lib/shuffle.rb, line 88
def construct_from(edge_hash, size)
  shuffled_sequence = edge_hash[start(size)].shift
  
  until edge_hash.values.flatten.empty?
    shuffled_sequence.concat(edge_hash[shuffled_sequence[-(size - 1)..-1]].shift[-1, 1])
  end
  
  shuffled_sequence
end
edge_list(size) click to toggle source
# File lib/shuffle.rb, line 58
def edge_list(size)
  sequence.each_cons(size).inject(Hash.new { |hash, key| hash[key] = [] }) do |hash, subsequence|
    hash.tap { hash[subsequence[0..-2]] << subsequence }
  end
end
frequency(array) click to toggle source
# File lib/shuffle.rb, line 98
def frequency(array)
  array.inject(Hash.new { |hash, key| hash[key] = 0 }) { |hash, token| hash.tap { hash[token] += 1 } }
end
last_edge_graph(edge_hash, size) click to toggle source
# File lib/shuffle.rb, line 68
def last_edge_graph(edge_hash, size)
  edge_hash.reject { |token, edges| token == terminal(size) }.values.map(&:last)
end
method_missing(name, *args, &block) click to toggle source
Calls superclass method
# File lib/shuffle.rb, line 102
def method_missing(name, *args, &block)
  if size = PREFIXES[name.to_s.match(/^(\w+)shuffle$/)[1]]
    shuffle(size.to_i)
  else
    super
  end
end
shuffle!(edge_hash) click to toggle source
# File lib/shuffle.rb, line 64
def shuffle!(edge_hash)
  edge_hash.tap { edge_hash.values.map(&:shuffle!) }
end
shuffler(size) click to toggle source
# File lib/shuffle.rb, line 40
def shuffler(size)
  if size == 1
    sequence.shuffle
  else
    edge_hash = shuffle!(edge_list(size))
    shuffle!(edge_hash) until connected?(last_edge_graph(edge_hash, size), size)
    construct_from(edge_hash, size)
  end
end
start(size) click to toggle source
# File lib/shuffle.rb, line 50
def start(size)
  sequence[0, size - 1]
end
terminal(size) click to toggle source
# File lib/shuffle.rb, line 54
def terminal(size)
  sequence[(-(size - 1))..-1]
end