作者: Hiroshi Shinohara
日時: 2003/8/03(22:38)
 風つかいです。
 くすのき@まっとうさん、こんにちは。

>クロスワードをといて最後に、指定の升目の文字を組み合わせて
>ヒントの文字を導き出すといった問題がありますが、それを AWK
>と、辞書ファイルから候補を全部探し出すプログラムを考えてみ
>ました。

 たとえば、こういうケースでしょうか?
  1)クロスワードパズルを解いていて、指定の升目の文字が
    全部ではないが分かっている。
    例えば、
     き?む?たく (6升目のうち、2つは不明。)
  2)ヒントでいくつか候補が考えられる。
    例えば、「SMAP」というヒントがあって、
     候補は、
      なかいまさひろ
      きむらたくや
      いながきごろう
      かとりしんご
      じやにーず
    とか考えられますのでこれを、辞書ファイルに入れておく。
   (ファイル名は、edict)
  3)升目の文字の組合わせを作成
  4)生成した文字列が辞書ファイルにあるかをチェック
  5)あれば書き出す。
    この例では、きむらたくや が合致する。
   (チェックのやり方は、辞書ファイルの文字列を並び変えて、升目の
    文字列になるか? を見ても良いとも思います。 辞書ファイル
    のサイズが小さければ、こちらの方が速い。)

 順列組合せの関数が既に作成済みなら、これでもプログラムしても
良いのですが、(私の場合持ち合わせがありませんので)、手抜きを
します。 解き方の一例としては、
  A1)辞書ファイルの文字列を、順に読み出して
  A2)文字数チェック(例では、6文字)
  A3)升目の文字を全部含むか?を照合
  A4)一致すれば、書き出し。

  AWKでは、連想配列を使うとプログラムが「速くて簡単」になりますので、
 順列組合せの文字列のチェックの代わりに、
   ・チェックの基準となる文字を連想配列に入れておいて、
   ・照合したい文字列に、連想配列の各文字が含まれるかチェック
    するやり方とします。
 A1〜4をこのやり方で修正すると、
  B1)分かっている升目の文字を、連想配列に格納
  B2)辞書ファイルの文字列を、順に読み出して
  B3)文字数チェック(例では、6文字)
     連想配列に含まれる文字が全て、辞書の文字列に現れるかチェック
  B4)全部含まれれば、書き出し。
 となります。

 これをプログラムすると、こんな感じになります。コマンドライン引数の
チェックは、だいぶ手抜きですが。

-----^ CROSS01.AWK ( date:03-08-03 time:21:58 ) ------------<cut here
####################
# クロスワード ヒント辞書検索
####################
# cross01.awk Rev.1.0 2003/08/03 windy 風つかい H.S.
####################
# Usage: jgawk -f cross01.awk 辞書ファイル名 升目文字 文字列長
#        jgawk -f cross01.awk edict きむたく 6

BEGIN{
  if(ARGC < 4) {                         # コマンドライン引数チェック
   Usage = "jgawk -f cross01 辞書ファイル名 升目文字 文字列長"
   print Usage > "/dev/stderr"
   exit
  }
  # コマンドライン引数処理
  MasumeMoji = ARGV[2]                   # 分かっている升目文字
  Mojisuu    = ARGV[3]+0                 # 照合文字数
  ARGV[2]    = ""  ; ARGV[3]    = ""     # 引数クリア

  # 連想配列に升目文字を格納
  count = jlength(MasumeMoji)            # 分かっている升目文字の数
  while (count > 0) {
    c = jsubstr(MasumeMoji,count,1)      # 1文字取り出し
    MojiMemo[c] = count                  # 値は何でも良い。
    count--                              # 次へ
  }
}

# 辞書ファイル処理
{
  if(jlength($0) != Mojisuu) next        # 字数チェック
  count = jlength(MasumeMoji)            # 分かっている升目文字の数
  for (cc in MojiMemo) {                 # 連想配列の文字が存在するかチェック
    if(jindex($0,cc) == 0) next          # 存在しなければ、次へ
    count--                              # 書き出しチェック用カウンタ
    if(count == 0) print $0              # 書き出し
  }
}
-----$ CROSS01.AWK ( lines:38 words:135 ) ------------------<cut here

 辞書は適当にこんな感じで。
-----^ EDICT ( date:03-08-03 time:15:50 ) ------------------<cut here
なかいまさひろ
きむらたくや
いながきごろう
かとりしんご
じやにーず
-----$ EDICT ( lines:5 words:5 ) ---------------------------<cut here

 コマンドラインから、
 jgawk -f cross01.awk edict きむたく 6 >aaa とすると、結果がファイルに落ちます。
-----^ AAA ( date:03-08-03 time:22:09 ) --------------------<cut here
きむらたくや
-----$ AAA ( lines:1 words:1 ) -----------------------------<cut here

風つかい(hshinoh@...)
IconのWWWは、  http://www.cs.arizona.edu/icon/
UniconのWWWは、http://unicon.sourceforge.net/index.html
BGM: Circulation / 杉本喜代志