SQLer 生島勘富 のブログ

RDB・SQLの話題を中心に情報発信をしています。

CODE VS 2.1 をSQLでやるとどうなる1

 CODE VS というコーディングコンテストに参加しました。

CODE VS 2.1 で勝てなかったからネタに

 結果は惨憺たるもので、私は1手読みまでで、Largeの条件で9億ぐらいのスコアー。時間とメモリーさえあれば無限に先読み(総当たりで)できるけれど、数手先まで伸ばしても同じスコアーでした。

 終わりの方に気づいたのですが、何手先まで読むかというのは間違いでした(当たり前)。1手読みでもう少しスコアーを伸ばせるエレガンスなロジックにして、それで違った条件の手が出現したとき(ブロックを消すべきか、積むべきか迷う局面)をターニングポイントとして記録。何らかの条件を満たしたときチェックポイントとして決め(例えば、ブロックを消す条件になったとき)そのときのスコアーなどが、目標を満たしてないとき、ターニングポイントまで戻る。

 というようなやり方ならもっと伸ばせたと思う。
 多分、上位の人は、もっとエレガンスなやり方をしていると思うけれど、私が思いついたのはその程度。

 何にしても、私はゲームをほとんどしたことがないためか、プログラム以前に、私自身が1ターン毎の局面で「何をもって良い手とするか」という条件を見いだすことができなかった。つまり、ターニングポイントも、チェックポイントも、私には良いものは選べなかったと思うので、スコアーを伸ばせるはずがない……。

 ぶっちゃけ、年齢的な衰えも相当に感じたorz
 思考力の瞬発力は確実に衰えているな〜、それにしても、後、何日かあれば……。 
 正直、子供っぽい性格なので本当に悔しい……。


 それはともかく、スコアーが出なかったのでじゃあ、ネタにしよう。ということにしました。

 私は Java で参戦したのですが、画面イメージは必要ありませんが、データ的には問題のゲームを完全に再現しなければ解けません。そこまでをSQLでやったらどうなるか?ということを書いてみたいと思います。

 ※ SQLServer2005以上を想定しています。

SQLでやる部分(基本設計)予定

 確認用(ある時点のボードの状態を確認する)
    SELECT文(PIVOT/クロス集計)
    数値羅列テーブル(再帰SQL・テーブルファンクション)

 Input情報をDBに入れる
    INSERT文(単純に入力する)

 以下を繰り返す
   Boardにパックを落とす
      INSERT SELECT文(一括挿入・分析関数)
      ※ パックの角度(4通り)× パックが置ける位置の通り

   ブロックを消せなくなるまで繰り返す。
    消せるブロックを探す
      INSERT SELECT文(一括挿入・再帰SQL・CROSS JOIN)
    消すお邪魔ブロックを探す
      INSERT SELECT文(一括挿入・再帰SQL・CROSS JOIN)
    パックを落とす
      INSERT SELECT文(一括挿入・分析関数)
   繰り返し終わり

   スコアーを計算する
      UPDATE SELECT文(一括更新・集計関数)

   良い手を探す(ここが私には分からない所)
      SELECT文(集計関数イロイロ)

   不要情報を消す ※特に必要ないけど、場合によってはエライ量になるので
      DELETE(一括削除)
 繰り返し終わり


 最終的にいろんなシミュレーションをしようと思えば、もっと必要になりますが、最低限であれば、SQL文が10個ぐらいあれば事足りる。

 ターン毎に区切るのはゲームの仕様上同じですが、Javaなどと違う点は、一気に全通りのパックを落としてしまうところ。この辺が集合理論の SQL の特徴です。
 業務SE・PGなら、問題を見た瞬間にこのぐらいまで行って欲しい。

 もちろん、上の様なロジックは、私は Javaなどでやる場合と、SQLでやる場合と、ほぼ同時に頭の中にあって、

   SQLは一回でできるし、状況も確認しやすいから楽。
   メモリーで完結するスピード勝負のコンテストでは SQL は不利。

 と判断しました。
 具体的な SQL は次回以降ボチボチ書いていきます。


 このぐらいが「SQL でできるよね」って判断している人は、実務で設計を考えるとき、全く違う景色で観ています。

 違う景色から観れば、RDBMSを使うなら SQL を使えば、工数もパフォーマンスも、本当に劇的に違うものになるのですけどね……。


※ 現在、サロゲートキーでしようか、ナチュラルキーでしようか悩み中