アナグラム・メーカー

ウェブアプリで考えるのではなく,コマンドライン上で動くものをまず作らない事には意味が無さそうなので,とりあえず考えはする.

事の発端

事の発端は某勉強会.いわゆる悪ふざけ.実用化されない.ちゃんと作り上げるかもわかんない.

最大の問題点

ただ文字の順番を入れ替えて表示するだけでは藝が無いし,辞書ファイルにある単語にマッチさせて,存在すれば表示,みたいな.
アナグラム - Wikipediaにも書いている事だけれど,

単純に考えてN文字ならNの階乗通り(例えば5文字なら120通り)の並べ替えが可能

だから,それをズラっと出すと大変な事になるのは目に見えている.
だから,ある程度の辞書が欲しい気がする.英単語ならEIJIROの辞書ファイルを使えば良さそうな気もするけれども,何処でも動くと言う前提が無くなるし,そもそも容量が大きすぎるので望ましくない.
もし日本語で使う事を仮定するなら,母音と子音を分け,それぞれの組み合わせで考えればまだ少なくなるかな?

プロトタイプ

何はともあれ,とりあえず動くものを作ろう.結果は全部出すんじゃなくて,ランダムでいいや.

class Array
  def shuffle!
    hoge = self.dup
    self.each_index do |i|
      e = rand(hoge.length)
      self[i] = hoge[e]
      hoge[e] = nil
      hoge.compact!
    end
  end
  
  def div_rand
    p = rand(self.length)
    
    before = self[0 .. p]
    after = self[p + 1 .. self.length - 1]
    
    return before, after
  end
end

def anagram(str = nil)
  return nil if str.nil?
  return str if str =~ /\d/
  
  alpha = str.split(//)
  
  # 母音を抜き出す
  vocals = alpha.select{|e| e =~ /[aiueo]/}
  vocals.shuffle! # 混ぜる
  # 子音を抜き出す
  cons = alpha.select{|e| e !~ /[aiueo]/}
  cons.shuffle! # 混ぜる
  
  # 母音が子音より多ければ母音を一個抜き出しておく
  if vocals.length > cons.length
    vocal = vocals.shift
  else
    vocal = nil
  end

  # 子音,母音,子音と繋げていく
  result = []
  cons.each do |e|
    result.push e, vocals.shift
  end

  before, after = result.div_rand # 適当な所で切る
  result = before << vocal << after
  
  # 強引
  return result.to_s
end

これでなんとかそれっぽい事はできる.

> anagram 'omochi'
=> "mihoco"

ミホコって誰.ボクのネカマハンドルにするか:p

課題

chなんかは一つに纏めてしまうってのもアリだなぁ.yやhは拗音に使えるし,この辺りも特別視すべきかな.この辺はイテレーションで.
できれば日本語で入力して日本語で吐き出したい.処理は勿論ローマ字に置き換えてやりたいな.ハッシュを使えば楽そうだ.

ミソ

このコードの場合だと,Array#shuffle!だけでほとんど終わってる.

> puts 'ほげ'.split(//u).shuffle!.to_s
げほ

やろうと思えば,これで良いんだもの.あとは以下にkewlにアナグラムるかだな.