Skip to content

Instantly share code, notes, and snippets.

@ParadoxV5
Created January 4, 2023 06:58
Show Gist options
  • Save ParadoxV5/db3dc31ba149e68e88f343bdee7e1a36 to your computer and use it in GitHub Desktop.
Save ParadoxV5/db3dc31ba149e68e88f343bdee7e1a36 to your computer and use it in GitHub Desktop.
# frozen_string_literal: true
# Assuming `PascalCase` only. Also possible: `English Case`, `Snake_Case`, …
DIGITS_CASES = %w[
zero
one
two
three
four
five
six
seven
eight
nine
].map.with_index {|word, i| [
i.to_s,
word,
word.upcase,
word.capitalize
] }
def number_cases(*nums)
return [] if nums.empty?
first, *rest = nums.map {|num| DIGITS_CASES[num] }
first.zip(*rest)
end
def cons_combinations(*objects)
combos = (1...objects.size).flat_map do|idx|
cons_combinations(*objects[idx..]).map { [objects[...idx], *_1] }
end
combos << [objects]
combos
end
# Search Space complexity: 4×5ⁿ⁻¹ = ⅘(5ⁿ) ∈ Θ(5ⁿ)
# Each additional digit make 5 variants:
# numeral, lower, upper, screaming,
# and (except for the units digit) repeat modifier
def iterate(number)
number = number.to_s
raise 'empty number' if number.empty?
return to_enum(__callee__ || :iterate, number) { 5**number.size.pred * 4 } unless block_given?
cons_combinations(*number.each_char.map(&:to_i)).each do|nums|
first, *rest = nums.map do|f, *num|
if num.empty?
# solo group, use for non-repeats
number_cases(f)
else
number_cases(*num).map { _1 * f }
end
end
first.product(*rest) { yield _1.join }
end
number
end
(2.0**-12).then {|r| iterate('12345678') { puts _1 if rand <= r } }
binding.irb
DIGITS_CASES: Array[Array[String]]
class Object
def number_cases: (*int nums) -> Array[Array[String]]
def cons_combinations: [E] (*E objects) -> Array[Array[E]]
def iterate:
(_ToS number) { (String) -> void } -> String
| (_ToS number) -> Enumerator[String, String]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment