HEXA BLOG

プログラム

HEXA BLOGプログラム2018.1.29

敵とか武器とかアイテムとか その4

先日、人生で初めてのスノーボードに行ったら、

偶然取材できていたラジオ局の人に

「今ラジオの企画で、最近の若者に取材をしてるんですが、大学生ですか?」

って話しかけられました。

溢れ出る若さが抑えきれないようです。

こんにちは、だっちです。

(雪ではしゃいで小さい雪だるまを作っていたから話しかけられたわけじゃないはず!

 

 

さて、前回に引き続きExcelで作成したデータから、

ゲーム内で扱いやすい形に変換するためのプログラムを実装していこうと思います。

 

前回は「クラスファイルの生成」を行うところまで出来たので、

今回は予定通り「データファイルの書き出し」を行っていきたいと思います。

 

ファイルの形式は、とりあえずXML形式で書き出していこうと思います。

前回までのプログラムを改良して、データファイルを書き出してきます。

 

データはこんな感じで用意してみました。

コードは長くなってしまったので一番下に載せておきます。

 

実際に生成されたXMLファイルはこんな感じです。

これで、「データファイルを書き出す」事ができましたね!

 

ただ、単純にXMLファイルを書き出すだけならExcel標準の機能でも行うことが出来ますし、

前回生成したクラスファイルも活用していなくてせっかく実装した恩恵が少ないですね。

 

次回からはもう少し便利になるように拡張していこうと思います。

 

ではでは~

 

 

以下ソースコードです。

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using NPOI.SS.UserModel;
using System.Xml;

namespace NPOITest
{
	class Program
	{
		// クラス情報
		private class ClassInfo
		{
			public string						name					{ get; }		//!< クラス名
			public string						desc					{ get; }		//!< クラス説明
			public List		memberVariableInfos		{ get; }		//!< メンバ変数情報

			// @brief	コンストラクタ
			// @param	[in]	name					クラス名
			// @param	[in]	desc					クラス説明
			// @param	[in]	memberVariableInfos		メンバ変数情報
			public ClassInfo(string name, string desc, List memberVariableInfos)
			{
				this.name					= name;
				this.desc					= desc;
				this.memberVariableInfos	= memberVariableInfos;
			}
		}

		// メンバ変数情報
		private class MemberVariableInfo
		{
			public string		name		{ get; }		//!< 変数名
			public string		type		{ get; }		//!< 型
			public string		desc		{ get; }		//!< 変数説明

			// @brief	コンストラクタ
			// @param	[in]	name	変数名
			// @param	[in]	type	型
			// @param	[in]	desc	変数説明
			public MemberVariableInfo(string name, string type, string desc)
			{
				this.name	= name;
				this.type	= type;
				this.desc	= desc;
			}
		}

		// データ
		private class Data
		{
			public List		records		{ get; }		//!< レコード

			// @brief	コンストラクタ
			// @param	[in]	records	レコード
			public Data(List records)
			{
				this.records = records;
			}
		}

		// データ1レコード
		private class Record
		{
			public List		values		{ get; }		//!< 値

			// @brief	コンストラクタ
			// @param	[in]	values	値
			public Record(List values)
			{
				this.values = values;
			}
		}

		private const string	TYPEDEF_SHEET_NAME			= "typedef";		//!< 「型情報定義」シート名
		private const string	DATA_SHEET_NAME				= "data";			//!< 「データ」シート名

		private const int		DATA_NAME_ROW				= 0;				//!< データ名行
		private const int		DATA_NAME_CELL				= 1;				//!< データ名列

		private const int		DATA_DESC_ROW				= 1;				//!< データ説明行
		private const int		DATA_DESC_CELL				= 1;				//!< データ説明列

		private const int		MEMBER_VARIABLE_START_ROW	= 10;				//!< メンバ変数開始行
		private const int		MEMBER_VARIABLE_NAME_CELL	= 1;				//!< メンバ変数名列
		private const int		MEMBER_VARIABLE_TYPE_CELL	= 2;				//!< メンバ変数型列
		private const int		MEMBER_VARIABLE_DESC_CELL	= 3;				//!< メンバ変数説明列
		private const int		MEMBER_VARIABLE_MAX			= 1024;				//!< メンバ変数最大許容数

		private const int		DATA_START_ROW				= 1;				//!< データ開始業
		private const int		DATA_START_CELL				= 1;				//!< データ開始列
		private const int		DATA_MAX					= 1024;				//!< データ最大許容数


		// @brief	エントリポイント
		public static void Main(string[] args)
		{
			// エクセルファイル入力受付
			Console.Write("Prease input excel file path : ");
			var srcPath = Console.ReadLine();

			// 読み込み
			ClassInfo classInfo = null;
			readExcelFile(srcPath, out classInfo);

			Data data = null;
			readExcelFile(srcPath, classInfo, out data);

			// クラスファイル書き出し先入力受付
			Console.Write("Prease input class file output directory : ");
			var outDirectory = Console.ReadLine();

			// 書き出し
			writeClassFile(outDirectory, classInfo);
			writeDataFile(outDirectory, classInfo, data);
		}

		// @brief	エクセルファイルの読み込み
		// @param	[in]	srcPath		読み込みファイル名
		// @param	[out]	classInfo	クラス情報
		// @return	なし
		private static void readExcelFile(string srcPath, out ClassInfo classInfo)
		{
			classInfo = null;

			// ファイル存在確認
			if( !File.Exists(srcPath) ) {
				Console.WriteLine("file not exists.");
				return;
			}

			var className			= string.Empty;
			var classDesc			= string.Empty;
			var memberVariableInfos	= new List();
			var records				= new List();
			using( var fs = new FileStream(srcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) ) {
				var workbook = WorkbookFactory.Create(fs);

				// 中にあるシートを順番に取得
				foreach( ISheet sheet in workbook ) {
					if( sheet == null ) continue;

					// シート名表示
					Console.WriteLine("	Name : " + sheet.SheetName);

					// シートの名前が「型情報定義」シート名だったら、型情報を読み込み
					if( sheet.SheetName == TYPEDEF_SHEET_NAME ) {
						Console.WriteLine();

						Console.WriteLine("Data");
						// データ名を取得
						className = getCellValue(sheet, DATA_NAME_ROW, DATA_NAME_CELL);
						if( string.IsNullOrWhiteSpace(className) ) {
							Console.WriteLine("DataName acquisition failed...");
						}
						else {
							Console.WriteLine("	Name : " + className);
						}

						// データ説明を取得
						classDesc = getCellValue(sheet, DATA_DESC_ROW, DATA_DESC_CELL);
						if( string.IsNullOrWhiteSpace(classDesc) ) {
							Console.WriteLine("DataDesc acquisition failed...");
						}
						else {
							Console.WriteLine("	Desc : " + classDesc);
						}

						// メンバ変数を取得
						Console.WriteLine("MemberVariables");
						for( int i = 0, row = MEMBER_VARIABLE_START_ROW; i < MEMBER_VARIABLE_MAX; ++i, ++row ) {
							// メンバ変数名を取得
							var memberName = getCellValue(sheet, row, MEMBER_VARIABLE_NAME_CELL);
							if( string.IsNullOrWhiteSpace(memberName) ) {
								Console.WriteLine("MemberName acquisition failed...");
								// メンバ変数名が空欄だったら終了と判断
								Console.WriteLine("End Of Member Variables");
								break;
							}

							Console.WriteLine("	[" + i + "]");
							Console.WriteLine("		Name : " + memberName);

							// メンバ変数型を取得
							var memberType = getCellValue(sheet, row, MEMBER_VARIABLE_TYPE_CELL);
							if( string.IsNullOrWhiteSpace(memberType) ) {
								// メンバ変数名が空欄だったら終了と判断
								Console.WriteLine("MemberType acquisition failed...");
							}
							else {
								Console.WriteLine("		Type : " + memberType);
							}

							// メンバ変数説明を取得
							var memberDesc = getCellValue(sheet, row, MEMBER_VARIABLE_DESC_CELL);
							if( string.IsNullOrWhiteSpace(memberDesc) ) {
								// メンバ変数名が空欄だったら終了と判断
								Console.WriteLine("MemberDesc acquisition failed...");
							}
							else {
								Console.WriteLine("		Desc : " + memberDesc);
							}

							memberVariableInfos.Add(new MemberVariableInfo(memberName, memberType, memberDesc));
						}
					}
				}
			}

			classInfo = new ClassInfo(className, classDesc, memberVariableInfos);
		}

		// @brief	エクセルファイルの読み込み
		// @param	[in]	srcPath		読み込みファイル名
		// @param	[in]	classInfo	クラス情報
		// @param	[out]	data		データ
		// @return	なし
		private static void readExcelFile(string srcPath, ClassInfo classInfo, out Data data)
		{
			data = null;

			// クラス情報有効性チェック
			if( classInfo == null ||
				classInfo.memberVariableInfos == null ||
				classInfo.memberVariableInfos.Count <= 0 ) {
				Console.WriteLine("\"classInfo\" is invalid.");
				return;
			}

			// ファイル存在確認
			if( !File.Exists(srcPath) ) {
				Console.WriteLine("file not exists.");
				return;
			}

			using( var fs = new FileStream(srcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) ) {
				var workbook = WorkbookFactory.Create(fs);

				// 中にあるシートを順番に取得
				foreach( ISheet sheet in workbook ) {
					if( sheet == null ) continue;

					// シート名表示
					Console.WriteLine("	Name : " + sheet.SheetName);

					// シートの名前が「データ」シート名だったら、レコードを読み込み
					if( sheet.SheetName == DATA_SHEET_NAME ) {
						Console.WriteLine();

						Console.WriteLine("Records");

						var valueMax = classInfo.memberVariableInfos.Count;
						var records = new List();
						// レコード数分ループ
						for( int rowIndex = DATA_START_ROW, recordCount = 0; recordCount < DATA_MAX; ++rowIndex, ++recordCount ) {
							var values = new List();
							var isEndRead = false;
							// メンバ変数分ループ
							for( int cellIndex = DATA_START_CELL, valueCount = 0; valueCount < valueMax; ++cellIndex, ++valueCount ) {
								// セルの内容取得
								var cellStr = getCellValue(sheet, rowIndex, cellIndex);

								// 1セル目が空白なら終了扱い
								if( valueCount == 0 &&
									string.IsNullOrEmpty(cellStr) ) {
									isEndRead = true;
									break;
								}

								Console.Write(cellStr + ", ");
								values.Add(cellStr);
							}
							if( isEndRead ) break;

							Console.WriteLine();
							records.Add(new Record(values));
						}

						data = new Data(records);
					}
				}
			}
		}

		// @brief	クラスファイルの書き出し
		// @param	[in]	outDirectory	書き出し先ディレクトリ
		// @param	[in]	classInfo		クラス情報
		// @return	なし
		private static void writeClassFile(string outDirectory, ClassInfo classInfo)
		{
			// 入力情報が不正なら終了
			if( string.IsNullOrWhiteSpace(outDirectory) ) {
				Console.WriteLine("outDirectory is invalid....");
				return;
			}
			if( classInfo == null ||
				string.IsNullOrWhiteSpace(classInfo.name) ||
				string.IsNullOrWhiteSpace(classInfo.desc) ||
				classInfo.memberVariableInfos == null ) {
				Console.WriteLine("classInfo is invalid...");
				return;
			}

			// 指定ディレクトリがなければ作成
			if( Directory.Exists(outDirectory) ) {
				Directory.CreateDirectory(outDirectory);
			}

			// ソースコード作成
			var sourceCode = new StringBuilder();

			// クラス開始
			sourceCode.AppendLine("// @class	" + classInfo.name);
			sourceCode.AppendLine("// @brief	" + classInfo.desc);
			sourceCode.AppendLine("public class " + classInfo.name);
			sourceCode.AppendLine("{");

			// プロパティ開始
			foreach( var memberVariableInfo in classInfo.memberVariableInfos ) {
				if( memberVariableInfo == null ||
					string.IsNullOrWhiteSpace(memberVariableInfo.name) ||
					string.IsNullOrWhiteSpace(memberVariableInfo.type) ||
					string.IsNullOrWhiteSpace(memberVariableInfo.desc) ) continue;

				sourceCode.AppendLine("	public " + memberVariableInfo.type + " " + memberVariableInfo.name + " { get; } //!< " + memberVariableInfo.desc);
			}
			sourceCode.AppendLine();
			// プロパティ終了

			// コンストラクタ開始
			sourceCode.AppendLine("	// @brief	コンストラクタ");
			// コンストラクタコメント
			foreach( var memberVariableInfo in classInfo.memberVariableInfos ) {
				if( memberVariableInfo == null ||
					string.IsNullOrWhiteSpace(memberVariableInfo.name) ||
					string.IsNullOrWhiteSpace(memberVariableInfo.type) ||
					string.IsNullOrWhiteSpace(memberVariableInfo.desc) ) continue;

				sourceCode.AppendLine("	// @param	[in]	" + memberVariableInfo.name + "	" + memberVariableInfo.desc);
			}
			// 引数
			var constructorArgs = new StringBuilder();
			foreach( var memberVariableInfo in classInfo.memberVariableInfos ) {
				if( memberVariableInfo == null ||
					string.IsNullOrWhiteSpace(memberVariableInfo.name) ||
					string.IsNullOrWhiteSpace(memberVariableInfo.type) ||
					string.IsNullOrWhiteSpace(memberVariableInfo.desc) ) continue;

				constructorArgs.Append(memberVariableInfo.type + " " + memberVariableInfo.name + ", ");
			}
			// 最後の不要な「, 」削除
			constructorArgs.Remove(constructorArgs.Length - 2, 2);
			sourceCode.AppendLine("	public " + classInfo.name + "(" + constructorArgs.ToString() + ")");
			sourceCode.AppendLine("	{");
			foreach( var memberVariableInfo in classInfo.memberVariableInfos ) {
				if( memberVariableInfo == null ||
					string.IsNullOrWhiteSpace(memberVariableInfo.name) ||
					string.IsNullOrWhiteSpace(memberVariableInfo.type) ||
					string.IsNullOrWhiteSpace(memberVariableInfo.desc) ) continue;

				sourceCode.AppendLine("		this." + memberVariableInfo.name + " = " + memberVariableInfo.name + ";");
			}
			sourceCode.AppendLine("	}");
			// コンストラクタ終了

			sourceCode.AppendLine("}");
			// クラス終了

			// 書き出し
			using( var sw = new StreamWriter(outDirectory + classInfo.name + ".cs", false, new UTF8Encoding(true)) ) {
				sw.Write(sourceCode.ToString());
			}
		}

		// @brief	データファイルの書き出し
		// @param	[in]	outDirectory	書き出し先ディレクトリ
		// @param	[in]	classInfo		クラス情報
		// @param	[in]	data			データ
		// @return	なし
		private static void writeDataFile(string outDirectory, ClassInfo classInfo, Data data)
		{
			// 入力情報が不正なら終了
			if( string.IsNullOrWhiteSpace(outDirectory) ) {
				Console.WriteLine("outDirectory is invalid....");
				return;
			}
			if( classInfo == null ||
				classInfo.memberVariableInfos == null ||
				classInfo.memberVariableInfos.Count <= 0 ) {
				Console.WriteLine("classInfo is invalid...");
				return;
			}
			if( data == null ||
				data.records == null ||
				data.records.Count <= 0 ) {
				Console.WriteLine("data is invalid...");
				return;
			}

			// 指定ディレクトリがなければ作成
			if( Directory.Exists(outDirectory) ) {
				Directory.CreateDirectory(outDirectory);
			}

			// ドキュメント作成
			var xmlDocument = new XmlDocument();

			// 定義、ルートノードを作成してドキュメントに追加
			var xmlDeclaration = xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", null);
			xmlDocument.AppendChild(xmlDeclaration);
			var xmlRoot = xmlDocument.CreateElement("root");
			xmlDocument.AppendChild(xmlRoot);

			var memberVariableInfos = classInfo.memberVariableInfos.ToArray();

			// レコードを全てルートに追加
			foreach( var record in data.records ) {
				var xmlRecord = xmlDocument.CreateElement(classInfo.name);

				var values = record.values.ToArray();

				// 値を全てレコードに追加
				for( var i = 0; i < memberVariableInfos.Length && i < values.Length; ++i ) {
					var xmlValue = xmlDocument.CreateElement(memberVariableInfos[i].name);
					xmlValue.InnerText = values[i];
					xmlRecord.AppendChild(xmlValue);
				}

				// ルートに追加
				xmlRoot.AppendChild(xmlRecord);
			}

			// ファイルに保存
			using( var sw = new StreamWriter(outDirectory + classInfo.name + ".xml", false, new UTF8Encoding(true)) ) {
				xmlDocument.Save(sw);
			}
		}

		// @brief	セルの値を取得
		// @param	[in]	sheet		シート
		// @param	[in]	rowIndex	行インデックス
		// @param	[in]	cellIndex	列インデックス
		// @return	セルの値
		private static string getCellValue(ISheet sheet, int rowIndex, int cellIndex)
		{
			if( sheet == null ) return string.Empty;

			// 行を取得
			var row = sheet.GetRow(rowIndex);
			if( row == null ) return string.Empty;

			// 行からセルを取得
			var cell = row.GetCell(cellIndex);
			if( cell == null ) return string.Empty;

			// セルが取得できたら中身を文字列化
			return cell.ToString();
		}
	}
}

RECRUIT

大阪・東京共にスタッフを募集しています。
特にキャリア採用のプログラマー・アーティストに興味がある方は下のボタンをクリックしてください

RECRUIT SITE