龍神録11章の改良プログラムへの質問

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
mj

龍神録11章の改良プログラムへの質問

#1

投稿記事 by mj » 13年前

こちらは龍神録11章で紹介されているをプログラムをDixqさんが改良したものですが
こちらに関して質問があります。
こちらより参照:
http://dixq.net/forum/viewtopic.php?f=3&t=9640#p77747

コード:

 
// 1行飛ばす
int SkipOneLine( int FileHdl ){
    int Ch;
    while( 1 ){
        Ch = FileRead_getc( FileHdl );
        if( Ch == -1 ){
            return -1;
        }
        if( Ch == '\n' ){
            return 0;
        }
    }
    return -1;
}
 
//敵の出現情報をエクセルから読み込んで格納する関数
void load_story(){
 
    int  FileHdl;//ファイルハンドル
    FileHdl = FileRead_open( "../dat/csv/11章/storyH0.csv" );//ファイル読み込み
    if( FileHdl == 0 ){ //読めなかったらエラー
        printfDx("read error\n");
        return;
    }
 
    SkipOneLine( FileHdl ) ;    //最初の二行は飛ばす
    SkipOneLine( FileHdl ) ;
 
    int n=0;
    int InputChar;  //一文字格納する入れ物
    int ScannedNum;     //スキャンできた個数
    while( 1 ){
        InputChar = FileRead_getc( FileHdl );//1文字取得する
        if( InputChar == '/' ){ //スラッシュがあれば
            SkipOneLine( FileHdl ) ;//一行読み飛ばし
            continue;
        } else {                //スラッシュじゃなければ
            FileRead_seek( FileHdl, -1, SEEK_CUR ) ;//さっき読んだ一文字戻す
        }
        //書式指定に応じて一行分読み込み
        ScannedNum = FileRead_scanf( 
            FileHdl,
            "%d,%d,%d,%lf,%lf,%lf,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
            &enemy_order[n].cnt,
            &enemy_order[n].pattern,
            &enemy_order[n].knd,
            &enemy_order[n].x,
            &enemy_order[n].y,
            &enemy_order[n].sp,
            &enemy_order[n].bltime,
            &enemy_order[n].blknd,
            &enemy_order[n].col,
            &enemy_order[n].hp,
            &enemy_order[n].blknd2,
            &enemy_order[n].wait,
            &enemy_order[n].item_n[0],
            &enemy_order[n].item_n[1],
            &enemy_order[n].item_n[2],
            &enemy_order[n].item_n[3],
            &enemy_order[n].item_n[4],
            &enemy_order[n].item_n[5]
        );
        if( ScannedNum != 18 ){ //18個全部読めなかったら処理を抜ける
            break;
        }
        n++;
    }
    FileRead_close( FileHdl );
}
読み込むファイルはプログラミングの館でダウンロードした下記ものを使用しております。

/カウンタ 移動パターン 敵の種類 x座標 y座標 スピード 発射時間 弾幕種類 弾の色 体力 弾種類 待機時間 アイテム1 2 3 4 5 6
/cnt pattern knd x座標 y座標 sp bltime blknd col hp blknd2 wait item_n[0]
100 0 0 50 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
110 0 0 80 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
120 0 0 110 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
130 0 0 140 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
140 0 0 170 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
150 0 0 200 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
160 0 0 230 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
170 0 0 260 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
180 0 0 290 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
190 0 0 320 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1

上記コードで気になるところですが
while( 1 ){
InputChar = FileRead_getc( FileHdl );//1文字取得する
if( InputChar == '/' ){ //スラッシュがあれば
SkipOneLine( FileHdl ) ;//一行読み飛ばし
continue;
} else { //スラッシュじゃなければ
FileRead_seek( FileHdl, -1, SEEK_CUR ) ;//さっき読んだ一文字戻す
}
こちらのwhile文のなかのスラッシュがあれば読み飛ばすという部分になります。
上記のファイルで数値が入っている行の最初のセルに/を入れてみたところその行だけ読み飛ばされる
のかと思ったのですが以降の普通の数値が記入されている行まで読み飛ばされてしまいます。

例えば5行目最初の[120]を[/120]に変更すると
/120 0 0 110 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
/を入れた行及び以降の行全て読み飛ばされます。下記も読み込まれません。
130 0 0 140 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
140 0 0 170 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
150 0 0 200 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
160 0 0 230 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
170 0 0 260 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
180 0 0 290 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
190 0 0 320 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
正確には読み飛ばすのではなくif(ScannedNum != 18)が成立してwhile文を抜けてしまっている気がします。
改良版ではない11章に記載されていたプログラムで同様のことをして実行すると5番目のenemyだけ表示されず、
正常にその行のデータだけ読み飛ばしてくれたことを確認しております。こちらの改良版のコードで同様の実行結果に
したい場合はどのようにすればよいのでしょうか。

自分なりに少しコードを変えてみたところこちらなら同様の実行結果が得られました。('/' を34に変えただけですが)
ただし、これだと行の最初のセルが文字列だった場合if文で読み飛ばすというような処理をしているので
行の最初以外のセルが文字列だった場合は有効ではないですね。
while( 1 ){
InputChar = FileRead_getc( FileHdl );//1文字取得する
if( InputChar == 34){ //ダブルクォーテーションであれば
SkipOneLine( FileHdl ) ;//一行読み飛ばし
continue;
} else { //ダブルクォーテーションじゃなければ
FileRead_seek( FileHdl, -1, SEEK_CUR ) ;//さっき読んだ一文字戻す
}

どなたかご教授お願い致します。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 龍神録11章の改良プログラムへの質問

#2

投稿記事 by みけCAT » 13年前

FileRead_scanf内でコンマを指定しているのに、ファイル内の区切りはスペースなので読み込めないのではないですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
Dixq (管理人)
管理人
記事: 1662
登録日時: 15年前
住所: 北海道札幌市
連絡を取る:

Re: 龍神録11章の改良プログラムへの質問

#3

投稿記事 by Dixq (管理人) » 13年前

> while文を抜けてしまっている気がします。

実際に確認してみてはいかがでしょうか。
ブレイクポイントを用いて一つずつどのように処理が行われているか確認してください。
特にSkipOneLineのFileRead_getcが何を取ってきていてどのように処理をしているか確認してください。
ブレイクポイントで一つずつ見ていけば必ず原因はわかるでしょう。

mj

Re: 龍神録11章の改良プログラムへの質問

#4

投稿記事 by mj » 13年前

>みけCATさん、ご返答ありがとうございます。

おそらくですが
FileHdl = FileRead_open( "../dat/csv/11章/storyH0.csv" );//ファイル読み込み
でファイルが読み込まれた際、1行内の文字列が
/カウンタ 移動パターン 敵の種類 x座標 y座標 スピード 発射時間 弾幕種類 弾の色 体力 弾種類 待機時間 アイテム1 2 3 4 5 6

"/カウンタ","移動パターン","敵の種類","x座標","y座標","スピード","発射時間","弾幕種類","弾の色","体力","弾種類","待機時間","アイテム1",2,3,4,5,6¥n
こんな感じに変換されているのでFileRead_scanfでも読み込めるのだと思います。
あくまで私の考えなので、もし間違っていたらスミマセン。

> Dixq さん、一応最初に自分でもステップ実行を行ってプログラミングの流れを確認しました。

SkipOneLine(FileHdl); //最初の二行は飛ばす
SkipOneLine(FileHdl);
実際のデータとは関係のない最初の2行は
Ch=FileRead_getc(FileHdl);の処理で1ループで1文字づつ取得して1行全ての文字の確認を行っています。

しかし、load_story()のwhile文では行の最初のセルの1文字目しかInputChar = FileRead_getc( FileHdl );
で取得していないため if( InputChar == '/' )の条件が成立することがないのではと思ったのです。
例に上げた/120 0 0 110 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1だと
"/120",0,0,110,-20,0,150,0,0,100,0,120,0,-1,-1,-1,-1,-1となっており、この行がFileRead_scanf()で
読み込まれるとScannedNum = 0となります。
そしてif(ScannedNum != 18)が成立し、whileのループを抜けてFileRead_close(FileHdl);へと至るという
流れになっていると思ったのですが間違っているでしょうか。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 龍神録11章の改良プログラムへの質問

#5

投稿記事 by softya(ソフト屋) » 13年前

プログラムで一文字目が/の場合のみがコメントです。
"/120",だとコメントとして成立してません。あと数値としても成立していないのでエラーになります。
最初の説明では書いてなかったので分かりませんでしたが、それだと仕様だと思います。

【補足】
方法は2つ有って、
(1)そう言うデータでもちゃんと受け付けられる様に改造する。
(2)そういうデータは作らないようにする。
いずれかです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

mj

Re: 龍神録11章の改良プログラムへの質問

#6

投稿記事 by mj » 13年前

> softya(ソフト屋)さん、ご解説ありがとうございます。

また、説明が不足していたようで申し訳ありません。
if(InputChar == '/')部分の処理はファイルのセル内に[/]があった場合
ではなくコメントがあった場合の処理だったのですね。その部分の処理を
考え違いしておりました。

ここで1つご質問があるのですがif(InputChar == '/')部分の条件を
あえて成立させたい場合はファイル内のセルにどのような記載があった
場合なのでしょうか。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 龍神録11章の改良プログラムへの質問

#7

投稿記事 by softya(ソフト屋) » 13年前

それはExcelの仕様ですね。
申し訳ないですが、手元にOpenOfficeしなかくExcelが無いので検証は難しいです。

OpenOfficeだと何も指定しないと次のようにcsvが作られます。
/あああああ,
/,いいいいいい
/9999,
/,
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

mj

Re: 龍神録11章の改良プログラムへの質問

#8

投稿記事 by mj » 13年前

> softya(ソフト屋) さん

なるほど、その部分のコードはExcelの仕様で書かれたものを処理するためのものだったのですね。
私もOpenOfficeしか持ち合わせていないため、Excelを使用してデータを作成する機会があったときに
試してみたいと思います。

此度もご解説の程、どうもありがとうございました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 龍神録11章の改良プログラムへの質問

#9

投稿記事 by softya(ソフト屋) » 13年前

mj さんが書きました:> softya(ソフト屋) さん

なるほど、その部分のコードはExcelの仕様で書かれたものを処理するためのものだったのですね。
私もOpenOfficeしか持ち合わせていないため、Excelを使用してデータを作成する機会があったときに
試してみたいと思います。

此度もご解説の程、どうもありがとうございました。
勘違いしていないか不安なので書いておきますが、
"/120"
の部分がちゃんと処理できない話ですよね?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

mj

Re: 龍神録11章の改良プログラムへの質問

#10

投稿記事 by mj » 13年前

>softya(ソフト屋) さん、解決済みとしたのにわざわざご返信ありがとうございます。

"/120"という文字列が入っている行を読み込んだときなぜwhile文をぬけるのか?
"/120"が入っている行をFileRead_scanf()で読み込もうとするとエラーが返されてしまうため、
if文のbreakが成立しwhile文を抜けてしまう。
(ScannedNum=0になってデータを18個読み込めていないと判断されている)
"/120"が処理できないところはこのような形で理解しました。

そしてif(InputChar == '/')はどのようなときに成立するのか?
そもそもここの処理はセルの中に[/]があった場合に読み飛ばすのではなくコメントとして文章が
入っていたときに成立する処理である。そして、そのコメントを入れるという処理を行うのは
Excelの機能としてのものである。つまり[/]を使ってコメント文を入れるというような機能が
Excelにはある。

このように自己解決したつもりでしたがまたどこかで考え違いをしていたのでしょうか。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 龍神録11章の改良プログラムへの質問

#11

投稿記事 by softya(ソフト屋) » 13年前

mj さんが書きました: そしてif(InputChar == '/')はどのようなときに成立するのか?
そもそもここの処理はセルの中に[/]があった場合に読み飛ばすのではなくコメントとして文章が
入っていたときに成立する処理である。そして、そのコメントを入れるという処理を行うのは
Excelの機能としてのものである。つまり[/]を使ってコメント文を入れるというような機能が
Excelにはある。
このように自己解決したつもりでしたがまたどこかで考え違いをしていたのでしょうか。
上はOKですが下が勘違いですね。
私が「特に指定なしにOpenOfficeで出力したcsvの場合」はとわざわざ書いたのはOpenOfficeで"/120"と出すこともできるからです。
文字列を"で囲んでcsvで出力する機能としてExcelにもありますが、OpenOfficeにもあります。

>Excelの機能としてのものである。つまり[/]を使ってコメント文を入れるというような機能がExcelにはある。

つまり、そんな機能は無いです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

mj

Re: 龍神録11章の改良プログラムへの質問

#12

投稿記事 by mj » 13年前

>softya(ソフト屋) さん

どうやら私の理解が及んでいないみたいですみません。少々混乱してしまっているので整理したいと思います。
softya(ソフト屋) さんが書きました:プログラムで一文字目が/の場合のみがコメントです。
"/120",だとコメントとして成立してません。あと数値としても成立していないのでエラーになります。
最初の説明では書いてなかったので分かりませんでしたが、それだと仕様だと思います。

【補足】
方法は2つ有って、
(1)そう言うデータでもちゃんと受け付けられる様に改造する。
(2)そういうデータは作らないようにする。
いずれかです。
まず、softya(ソフト屋) さんが最初におっしゃっていた「プログラムで一文字目が/の場合のみがコメントです。」は
つまり、プログラミング上でコメントや説明を記述したいときに使用する[//~]や[/*~*/]のことをおっしゃっていたの
だと思います。そしてcsvファイル上のセルに/120と記述したとしてもプログラミング(FileRead_open())で読み込むと
"/120",となってしまうためコメントとして成立しない。だからこのif(InputChar == '/')のコードは成立しない。
また、これは数値ではないためFileRead_scanf()で読み込めずにエラーとなる。ここまでは理解できます。

その後の「if(InputChar == '/')はどのようなときに成立するのか?」という私の問いかけに
softya(ソフト屋) さんが書きました:それはExcelの仕様ですね。
申し訳ないですが、手元にOpenOfficeしなかくExcelが無いので検証は難しいです。

OpenOfficeだと何も指定しないと次のようにcsvが作られます。
/あああああ,
/,いいいいいい
/9999,
/,
と返答してくれました。私は下記龍神録のcsvサンプルデータ(ここは何のデータでも良いのですが)を
書き換えてこのようなデータが書かれていたときにif(InputChar == '/')が成立するということを試して
みたかったのですがそれはExcelの仕様だということを聞いてExcelデータでなければif文を成立する
データを書くことができないのかと勘違いしたわけですね。
データはここからダウンロードしました。
http://dixq.net/rp/11.html

問題はそのあとのsoftya(ソフト屋) さんが「OpenOfficeで出力したcsvの場合」という解説をしてくださって
いるのですが上記の内容からこの部分への文章の繋がりがおそらく理解できていないのだと思います。

なぜ「if(InputChar == '/')が成立する場合のcsvファイル内でのデータの書き方は?」が

「OpenOfficeでのcsvの作られ方」
という流れになっているのかということを申し訳ありませんがご説明お願い致します。

理解力が足りずに申し訳ありません。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 龍神録11章の改良プログラムへの質問

#13

投稿記事 by softya(ソフト屋) » 13年前

まず、理解する必要があるのはif(InputChar == '/')と言う条件判断が何のために龍神録に必要かという話です。
それはどう思われていますか? この機能を簡単に言葉で表すとなんでしょうか?
これが分かっていないとプログラムの意図を理解していない事なります。

それと文字列をダブルクォートで囲むのはExcelがcsvに出力するとき自動で行なってしまう場合があります。
そういう意味での"/120",となるのは「Excelの仕様です」と言う私の説明になるわけです。
別段、直接テキストエディタで編集したり、OpenOfficeでも文字列をダブルクォートで囲んで出力させることは可能です。

それと「プログラミング(FileRead_open())で読み込むと"/120",となってしまうため」の様な事は決してありません。
ぜひ確認してみて下さい。
"/120",と言うデータが何処で発生したのか原因を確かめられるのは、データを持っているmjさんだけです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

mj

Re: 龍神録11章の改良プログラムへの質問

#14

投稿記事 by mj » 13年前

>softya(ソフト屋)

if(InputChar == '/')←この機能を簡単に言葉で表すとなんでしょうか?
簡単に言うならばコメント行を飛ばすための処理。
プログラミング上で[//これはコメントです]や[/*ここからは説明文*/]などこのようなコメント文を読み込んだときに
読み飛ばすためのものだと思われます。だから/がヒットしたときなんですね。

Excel上の仕様というのはセルに文字列を入力してそれをcsvで保存(出力)すると自動的にその文字列を
[" "]ダブルクォーテーションで囲ってしまう場合があるということだったんですねようやく理解できました。

プログラミング(FileRead_open())で読み込むと"/120",となってしまうのは私の勘違いでした。
Ch=FileRead_getc(FileHdl);で変数Chに格納される文字をprintfで出力したところ文字列に該当する部分に
[" "]ダブルクォーテーションが使用されることを確認しました。

コード:

 
int Ch;
	int cnn=0;//ループカウント
	while(1)
	{	Ch=FileRead_getc(FileHdl);
		cnn++;
		printfDx("cnn=%d,Ch=%c\n",cnn,Ch);
		if(Ch==-1)//エラー発生
			return -1;//SkipOneLine()に-1が返される
		}
		if(Ch=='\n')//改行だったとき
			return 0;//SkipOneLine()に0が返される
		}
	}
 

あともし"/120",というデータが何処かで発生したものと思われているのなら誤解をさせてしまい申し訳ありません。
"/120",というのは最初に書きました以下のcsvデータにて最初に120と記載されている行のデータに私自身が
120の部分を/120と書き換えた場合にif(InputChar == '/')で読み飛ばしてくれるのかを検証したものです。
実際は["/120",]はコメントではないので成立しないことは以前のご説明で確認をしております。つまり私は
if(InputChar == '/')はコメント行を飛ばす処理ではなく単に行の最初のセルに/(スラッシュ)があった場合
その行を読み飛ばすのだと勘違いしていたわけですね。

100 0 0 50 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
110 0 0 80 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
120 0 0 110 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
130 0 0 140 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
140 0 0 170 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
150 0 0 200 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
160 0 0 230 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
170 0 0 260 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
180 0 0 290 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1
190 0 0 320 -20 0 150 0 0 100 0 120 0 -1 -1 -1 -1 -1

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 龍神録11章の改良プログラムへの質問

#15

投稿記事 by softya(ソフト屋) » 13年前

それでOKだと思います。
龍神録の仕組みは行の一文字目に/があるときだけコメントと見なしています。
それ以外のパターンのコメントにも対応出来るように改造してみるのも良いかもしれませんね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

mj

Re: 龍神録11章の改良プログラムへの質問

#16

投稿記事 by mj » 13年前

softya(ソフト屋) さん、ありがとうございます。

外部ファイルからのデータの読み込みの方法は中々に奥が深いようです。今度、様々なデータパターンを
作って色々と試してみます。とりあえず、if(InputChar == '/')処理の疑問はようやく解決いたしました。

此度も長々とお付き合いくださりありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る