Excelでのデータ管理方法

投稿者: | 2012年5月22日

Excelでのデータ管理方法について解説します。

Excelでデータ管理をすると、

  • 表形式のデータを管理しやすい(データの挿入・削除が容易)
  • セルに色をつけて、目印をつけやすい
  • 数式を使って、条件式をあらかじめ計算できる(プログラム側のチェックコードが削減できる)

などのメリットが得られます。

単なる設定ファイルであればINIファイルやYAMLが有利ですが、RPG・SLGのような巨大なデータベースを扱うゲームではExcelが便利です。(本当に巨大なデータベースを使うMMORPGのようなジャンルでは、Oracleのようなリレーショナルデータベースを使うべきですけど…)

表形式のデータを使うゲーム

表形式のデータを使うようなゲームをリストアップしてみます。

  • RPGの敵テーブル
  • RPGのアイテムテーブル
  • SLGのユニットパラメータ
  • ステージ情報管理

例えば、RPGのアイテムテーブルの例です。

特にRPGは膨大なデータ量を扱うので、このような表形式のデータ構造でないと、調整がかなりつらいかと思います。

これはステージ情報の例です。

こんな感じで、Excelは表形式のデータ構造を管理するのに向いています。

読み込み方法

読み込み方法について考えてみます。

  1. Excelを直接読み込む
  2. CSVを直接読み込む
  3. ExcelをCSVに変換して読み込む
1.Excelを直接読み込む

環境によっては問題ない場合もありますが、たいていExcelを直接読み込もうとすると、Win32OLEを使える環境を作らないといけないので、ちょっと不便です。

2.CSVを直接読み込む

そこで、表形式であるCSVファイルを読み込むことを考えてみます。

確かにCSVは単なるテキストファイルですので、実行環境でロードするのが簡単です。

ですが、データ入力がやや不便です。例えば、書式(色をつけたりする)が保存できないとか、数式が使えません。

3.ExcelをCSVに変換して読み込む

そこで、ExcelをCSVファイルに一度変換して、CSVファイルを読み込むようにします。

すると、データ入力もExcelの便利な機能が使え、CSVなのでファイルのロードも簡単です。

ただ、Excelを編集するたびに変換処理を通さなければいけないのが少し面倒かもしれません。


まとめ

とまあ、色々考えてみましたが、「3.ExcelをCSVに変換して読み込む」が一番便利なのではないかと思います。

理由としては

  • データ管理の自由度が高い(Excelがそのまま使える)
  • データのロードが容易(CSVならロード処理が簡単に書ける)

だからです。問題のコンバート処理の手間ですが、バッチファイルを書いてデータ修正のたびにバッチファイルを起動すれば、それほどの手間ではないと思います。

ExcelをCSVに変換する方法

では、まずExcelをCSVに変換する方法を説明します。色々実装方法はあるかと思いますが、単にCSVとして出力するのではなく以下の機能を持たせてみました。

  • 「#」が一列目にあったら、コメント行として扱う
  • 「define」という定数シートを定義できるようにした
  • C言語形式のヘッダファイルをインクルードできるようにした(実行環境と定数を共有化する)
  • UTF-8へのエンコードが可能

xls2csv

ツール一式をZIPで用意しました。

内容としては、以下のようになります。

  • info.xls …入力データ
  • xls2csv.rb …ExcelをCSVファイルに変換するRubyスクリプト
  • define.rb …C言語形式のヘッダファイルをロードするRubyスクリプト
  • utf8.mac …文字コードをUTF-8に変換する秀丸のマクロ(秀丸のインストールが必要です)
  • define.d …C言語形式のヘッダファイル
  • buildXls.bat …Excelをコンバートするバッチファイル

[Ruby](http://www.ruby-lang.org/ja/)のインストールが必要ですが、インストールしてしまえばbuildXls.batを起動すればコンバートできます。

CSVを実行環境でロードする方法

例えば、こんなテーブルを読み込んだとします。

name hp mp str vit agi dex int luk
戦士 100 15 10 10 3 5 4 2
盗賊 80 20 5 6 8 12 7 8
僧侶 50 100 3 5 5 8 13 5

データ取得のインターフェースはこんな感じにします。

 CsvData* pData = Csv.GetCsvData("戦士"); // 戦士のデータを取得
 int hp = pData->GetInt("hp");
 int mp = pData->GetInt("mp");

内部的には文字列を連想配列で保持しておき、名前でアクセスできるようにします。メモリ使用量は多いですが、小~中規模なゲームではそれほど問題にならないと思います。もし、厳密な型チェックが必要であれば、連想配列は使わずに構造体・クラスのメンバ変数に値を入れるようにします。