メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
プログラマ見習い
記事: 44
登録日時: 5年前

メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#1

投稿記事 by プログラマ見習い » 5年前

 プログラマ見習いです。
 DXライブラリとVisalStudio2017communityを利用しています。

 次のマップデータを読み込みたいのですが出来ません。
 次のマップデータは、ご覧の通り、カンマで区切っている2桁で一組の文字列で出来ています。
 次のマップデータを読み込むには、次の課題をクリアしなければなりません。
  1.カンマを読み込まないで読み込みたい文字列だけを読み込む。
  2.00,11,AAなど、一組の文字列として読み込む。

コード:

 
 
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
00,00,00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00


  


 以上のマップデータを読み込むために、書籍やネットなどの情報を参考に、考えられる方法を試しました。
 しかし、すべて失敗してフリーズしてしまいました。

 ソースコードは、「配列とfor文を使っているのに画像が一つしか表示されない。」に体裁されたものに、
ファイル読み込み用関数void MapLoad();を追加したものです。
 画像は、以前、みけCATさんが投稿してくれたものそのまま利用するのはいかがなものかと思ったので、
参考にして自分で描いたものを投稿します。

 ファイル読み込みのソースコードはvoid MapLoad(){}の中に書いています。

 一つは、以下のようにsscanf_s();関数で分割する方法です。
 しかし、失敗してフリーズしてしまいました。

 方法1

コード:

 
 
#include <DxLib.h>



#define MAPSIZE 32 //マップサイズを決めます。

#define HEIGHT 15 //Y座標の最大値を決めます
#define WIDTH 40 //X座標の最大値を決めます

 //キャラクターの数の最大値を決めます。念のために多めにします。今回はマップデータの数に合わせます。
#define CHARA HEIGHT*WIDTH



 //画像データの構造体を作ります。
 //画像データは無理に配列やポインタで整理しようとすると、エラーやフリーズの原因になります。
struct ImageData{

 int kabe01; //
 int teki0A[2]; //

};

struct ImageData im; //



 //各キャラクターのデータの構造体を作ります。
struct CharaData{

 //int *ghandle; //アニメーションさせるために画像データハンドル。
 //ポインタ設定をしたが、これが原因の一つでした。

 char kind; //キャラクターの種類を格納。
 int anime_pattern; //アニメパーン数
 float x; //座標はfloatにします。
 float y;
 int body; //体力

};

struct CharaData charadata[CHARA]; //今回はcharadataと名づけます。
 //キャラクターは複数出現させるので、配列内に各キャラクターの最大値CHMAXを格納します。

//struct CharaData im[2]; //画像を描画するための変数。
//or//struct CharaData im[CHARA]; //画像を描画するための変数。



 //アニメーションカウンター用の変数を作ります。
unsigned int g_anime_counter=0;



 //マップデータを作ります。
char mapdata[HEIGHT][WIDTH];



  //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp==FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp=NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }



/////////////////////////////ここから////////////////////////////


 int x=0;
 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){

  //1024が1023に減っているのは、NULL文字対策
 FileRead_gets(buf,1023,fp); //ファイルを一行読み込む

 char c[WIDTH];
             //01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40
 sscanf_s(buf,"%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
"&c[0]","&c[1]","&c[2]","&c[3]","&c[4]","&c[5]","&c[6]","&c[7]","&c[8]","&c[9]",
"&c[10]","&c[11]","&c[12]","&c[13]","&c[14]","&c[15]","&c[16]","&c[17]","&c[18]","&c[19]",
"&c[20]","&c[21]","&c[22]","&c[23]","&c[24]","&c[25]","&c[26]","&c[27]","&c[28]","&c[29]",
"&c[30]","&c[31]","&c[32]","&c[33]","&c[34]","&c[35]","&c[36]","&c[37]","&c[38]","&c[39]");


 mapdata[y][x] = c[x];
 //FileRead_gets(mapdata[y], c[x], fp);
 //FileRead_gets(mapdata[y], buf[x], fp);
 //FileRead_gets(mapdata[y], buf[WIDTH], fp);

 x++;

 } //for(int x=0;x<WIDTH;x++)
} //for(int y=0;y<HEIGHT;y++)の最後

/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後



 //画像をロードする関数を作ります。
void Load(){

 im.kabe01=LoadGraph("media/kabe01.bmp");

 LoadDivGraph("media/teki0A.bmp",2,2,1,32,32,im.teki0A);

}



 //初期化用の関数を作ります。
void Init(){

  //キャラクターをカウントする変数を作ります。必要な変数の一つです。
  //キャラクターをカウントする変数はローカル変数でも問題ありませんでした。
 int counter=0;

 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){

  char c=mapdata[y][x];

   //初期化してマップデータから、キャラクターのデータを取り出します。

   //kindにマップデータを代入します。
   //これも必要な変数の一つです。
  charadata[counter].kind=c;

  charadata[counter].x=(float)x*MAPSIZE;
  charadata[counter].y=(float)y*MAPSIZE;

  int charaValid=0;
   //この変数を利用しないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   //Validは英語で「有効、根拠の確実な、確かな、正当な」などの意味です。

   //キャラクターごとに異なるものはswicth文を使います。
  switch(c){ //なお、ここにcounterを入れてしまうと、フリーズしてしまいました。
   case '11':
    charadata[counter].body=1;
    charaValid=1; //case毎にcv=1;と代入します。
    break;

   case 'AA':
    charadata[counter].anime_pattern=2; //アニメーションさせる場合はここで代入します。
    charadata[counter].body=1;
    charaValid=1; //
    break;

  }

    //このif文がないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   if(charaValid){
   mapdata[y][x]='0'; //マップデータを'0'にする事で、データの取り出しは終わりです。
    //ここでキャラクターの数を一つずつ増やしていきます。
   counter++;
   }

  }
 }

}


 //描画と移動処理用の関数を作ります
void Move(){

 for(int i=0;i<CHARA;i++){

  char c=charadata[i].kind;

  switch(c){
   //ここにcharadata[i].kindではなくiを入れると、一つしか描画されませんでした。
   //また、フリーズしてまった場合もあります。

   case '11':
    DrawGraph(charadata[i].x,charadata[i].y,im.kabe01,TRUE);
  
    break;

   case 'AA':
    int a=g_anime_counter/20%charadata[i].anime_pattern;
    DrawGraph(charadata[i].x,charadata[i].y,im.teki0A[a],TRUE);

    break;

  }

   //キャラクター単位で動かす方法でマップスクロールを行います。
  charadata[i].x=charadata[i].x-1;

 }

}



 //WinMain関数の中に、先ほど作った関数を入れます。//Move();だけwhile内に入れます。
int WINAPI WinMain(HINSTANCE hI,HINSTANCE hP,LPSTR lpC,int nC){

 if(ChangeWindowMode(TRUE)!=0) return -1; //ウィンドウモードの変更
 if(DxLib_Init()!=0) return -1; //DXライブラリ初期化処理
 if(SetDrawScreen(DX_SCREEN_BACK)!=0) return -1; //描画先を裏画面に設定


 //ロードの関数は、ここではここに入れます。


 MapLoad(); //マップデータのロード

 Load(); //画像のロード 

 Init(); //初期化。//if(charaValid)に関するコードを書いていない時は、ここに置かないで、while文の中に置くと、適切に描画されません。



 while(ProcessMessage()==0&&CheckHitKey(KEY_INPUT_ESCAPE)==0){
  //メッセージ処理(XキーかAlt+F4キーが押されたら終了)
  //ESCキーが押されたら終了
 if(ClearDrawScreen()!=0) return -1; //裏画面を消す


  //Init(); //初期化。//if(charaValid)に関するコードを書いていないでwhile文の中に初期化関数Init();置くと、適切に描画されません。
   //この関数をそのままwhile文の中に入れてしまうと、一番最初の画像が消えてしまう。

  Move(); //画像の描画と移動用の関数をここに置きます。

  g_anime_counter++; //



  if(ScreenFlip()!=0) return -1; //裏画面を表画面に反映

 }

 if(DxLib_End()!=0) return -1; //DXライブラリの終了処理
 return 0; //ソフトの終了

}

 



 以下はvoid MapLoad(){}の中身だけを投稿します。

 次に、カンマや改行を調べて、それをヌル文字に変換する方法も試してみました。



 方法2

コード:

 

 //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp==FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp=NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }


/////////////////////////////ここから////////////////////////////


 char c=0; //文字を読み込む
 int i=0; //文字列のデータのカウント

  //1024が1023に減っているのは、NULL文字対策
 while(FileRead_gets(buf,1023,fp)!='\n'); //改行に来たら読み込みを辞める



 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){

   //1024が1023に減っているのは、NULL文字対策
 c=FileRead_gets(buf,1023,fp);
 buf[i]=c;

 if(buf[i]==','||buf[i]=='\n'||buf[i]==EOF){
  buf[i]='\0'; //ヌル文字を代入
  i=-1; //カウントをリセットする。
  } //if(buf[i]==','||buf[i]=='\n'||buf[i]==EOF)の最後


 //いずれもフリーズしました。
 //mapdata[y][x]=buf[i];
 //FileRead_gets(mapdata[y],buf[i],fp);

 if(c==EOF) break;

  i++;


  } //for(int x=0;x<WIDTH;x++)の最後
 } //for(int y=0;y<HEIGHT;y++)の最後



/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後

 



方法3

コード:

 
 
  //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp==FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp=NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }


/////////////////////////////ここから////////////////////////////


 int i=0; //文字列データのカウント

 for(int y=0;y<HEIGHT;y++){

   //1024が1023に減っているのは、NULL文字対策
  FileRead_gets(buf,1023,fp);

  //for(int x=0;x<WIDTH;x++){

 if(buf[i]==','||buf[i]=='\n'||buf[i]==EOF){
  buf[i]='\0'; //ヌル文字を代入
  i=-1; //カウントをリセットする。
  } //if(buf[i]==','||buf[i]=='\n'||buf[i]==EOF)の最後

 
 //mapdata[y][x]=buf[x];
 FileRead_gets(mapdata[y],buf[i],fp);

  i++;


  //} //for(int x=0;x<WIDTH;x++)の最後


 } //for(int y=0;y<HEIGHT;y++)の最後



/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後

  



 mapdataを二次元配列から一次元配列にする方法も試しました。

コード:

 

 //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp==FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp=NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }


/////////////////////////////ここから////////////////////////////

  //1024が1023に減っているのは、NULL文字対策
 while(FileRead_gets(buf,1023,fp)!='\n'); //改行に来たら読み込みを辞める


 int x=0;
 for(int y=0;y<HEIGHT;y++){

   //1024が1023に減っているのはヌル文字対策
  fp=FileRead_gets(buf,1023,fp);

 //for(int x=0;x<WIDTH;x++){

 if(buf[x]==','||buf[x]=='\n'||buf[x]==EOF){
  buf[x]='\0'; //ヌル文字を代入
  x=-1; //カウントをリセットする。
  } //if(buf[x]==','||buf[x]=='\n'||buf[x]==EOF)の最後


  mapdata[y*WIDTH+x]=buf[x];

   x++;

  //} //for(int x=0;x<WIDTH;x++)の最後
 } //for(int y=0;y<HEIGHT;y++)の最後



/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後

 


 しかし、どれも失敗してフリーズしてしまいました。

 さらに、読み込んだデータをmapdataの中に変換や代入する方法も、分かりません。

 お手上げです。

 どのソースコードをどのように直せば、カンマ付き文字列のデータの読み込みが出来るようになるでしょうか。


 
添付ファイル
teki0A.jpg.jpg
teki0A.jpg.jpg (1.59 KiB) 閲覧数: 47516 回

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#2

投稿記事 by プログラマ見習い » 5年前

添付ファイルの投稿に失敗したので、あらためて投稿します。
添付ファイル
teki0A.jpg.jpg
敵AA
teki0A.jpg.jpg (1.59 KiB) 閲覧数: 47515 回
kabe01.jpg.jpg
壁11
kabe01.jpg.jpg (1.08 KiB) 閲覧数: 47515 回

アバター
usao
記事: 1889
登録日時: 11年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#3

投稿記事 by usao » 5年前

=と==の違い,わかってますかね?

FileRead_gets()の戻り値はググった感じだと「長さ」らしいですが,
だとしたら,↓って何の判定なのかわからないですよね.

コード:

FileRead_gets(buf,1023,fp)!='\n'
#方法論がどうの以前に最低限のことはしようぜ

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#4

投稿記事 by プログラマ見習い » 5年前

usaoさん。分かっています。ソースコードを書き直す際に書き間違えただけです。手書きでソースコードを書けば、誰にでも失敗があって、見落としてしまう事はありますよ。

アバター
usao
記事: 1889
登録日時: 11年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#5

投稿記事 by usao » 5年前

OK.他者に期待.
オフトピック
ソースをどう直したらいいか? という話をする際には,私なら,コードをコピー&ペーストする.

「ここに提示したコードは実際のものとは異なっていて,そりゃあ書き写しのミスもありますよ」とか言われても,
じゃあどれがそのミスで,どれは違うのか?
一体何に注目してどの問題について論じれば良いのか?
第三者には判断材料がないわけだから,正常なやりとり自体が不可能ですな.
(それでも大丈夫なエスパーな人もいるかもだが,私には無理)

Math

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#6

投稿記事 by Math » 5年前

>以上のマップデータを読み込むために、書籍やネットなどの情報を参考に、考えられる方法を試しました
本当に(^^

相当頭が混乱して様ですね。

まず char型 のデータに 2文字の文字列がはいるわけないじゃん!

--------------------------------------------------------
switch(c){ //なお、ここにcounterを入れてしまうと、フリーズしてしまいました。
case '11':
charadata[counter].body=1;
charaValid=1; //case毎にcv=1;と代入します。
break;

case 'AA':
charadata
--------------------------------------------------------

の'11'  と 'AA' はVS2019 では ワーニングがでて  '1' と 'A' に切り詰められますよ。


当然ながらデータ読み込みのところは大間違い!

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#7

投稿記事 by かずま » 5年前

media/map1 ですが、提示されたものは、空行 2行、データ 11行、空行 3行
になっていますよ。いいんですか?

media/map1 は CSVファイルである必要はありませんよね。
次のように変更してみました。読み込みが楽になります。

コード:

0000000000000000000000000000000000000000
0000000000111111111100000000001111111111
000000000000A000000000000000000000000000
0000000000000000000000000000000000000000
0000000000A00000000000000000000000000000
0000000000000000000000000000000000000000
00000000000A0000000000000000000000000000
0000000000000000000000000000000000000000
0000000000A00000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
char の変数に入らない '11' や 'AA' などのデータを使わず、
'0'、'1'、'A' にしました。

media/kabe01.bmp と media/teki0A.bmp を適当に作ったら、
次のプログラムで動きました。

コード:

#include <DxLib.h>

#define MAPSIZE 32

#define HEIGHT 15
#define WIDTH  40

#define CHARA (HEIGHT * WIDTH)

struct ImageData {
	int kabe01;
	int teki0A[2];
};

struct ImageData im;

struct CharaData {
	char kind;
	int anime_pattern;
	int x, y;
	int body;
};
int counter;  // ★

struct CharaData charadata[CHARA];
unsigned int g_anime_counter = 0;
char mapdata[HEIGHT][WIDTH];

void MapLoad()
{
	ZeroMemory(charadata, sizeof(charadata));

	char buf[1024];
	strcpy(buf, "media/map1");
	int fh = FileRead_open(buf);
	if (fh == NULL) { printfDx("ファイル読み込みエラー"); return; }

	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fh) == -1) break;
		memcpy(mapdata[y], buf, WIDTH);
	}
	FileRead_close(fh);
}

void Load()
{
	im.kabe01 = LoadGraph("media/kabe01.bmp");
	LoadDivGraph("media/teki0A.bmp", 2, 2, 1, 32, 32, im.teki0A);
}

void Init()
{
	counter = 0;
	for (int y = 0; y < HEIGHT; y++) {
		for (int x = 0; x < WIDTH; x++) {
			char c = mapdata[y][x];
			charadata[counter].kind = c;
			charadata[counter].x = x * MAPSIZE;
			charadata[counter].y = y * MAPSIZE;
			switch (c) {
			case '1':
				charadata[counter].body = 1;
				mapdata[y][x] = '0';
				counter++;
				break;
			case 'A':
				charadata[counter].anime_pattern = 2;
				charadata[counter].body = 1;
				mapdata[y][x] = '0';
				counter++;
				break;
			}
		}
	}
}

void Move()
{
	for (int i = 0; i < counter; i++) {  // ★
		char c = charadata[i].kind;
		switch (c) {
		case '1':
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
			break;

		case 'A':
			int a = g_anime_counter / 20 % charadata[i].anime_pattern;
			DrawGraph(charadata[i].x, charadata[i].y, im.teki0A[a], TRUE);
			break;
		}
		charadata[i].x = charadata[i].x - 1;
	}
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
	if (ChangeWindowMode(TRUE) != 0) return -1;
	if (DxLib_Init() != 0) return -1;
	if (SetDrawScreen(DX_SCREEN_BACK) != 0) return -1;

	MapLoad();
	Load();
	Init();

	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		if (ClearDrawScreen() != 0) return -1;
		Move();
		g_anime_counter++;
		if (ScreenFlip() != 0) return -1;
	}

	if (DxLib_End() != 0) return -1;
	return 0;
}

Math

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#8

投稿記事 by Math » 5年前

14歳からはじめるC言語わくわくゲームプログラミング教室 (DXライブラリー使用)
https://www.rutles.net/products/detail. ... uct_id=591

コード:

#include "gamemain.h"

int g_mapdata[MAP_HEIGHT][MAP_WIDTH] = {
	//0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },	//0
	{ 1, 7, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 4 },	//1
	{ 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 9 },	//2
	{ 1, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1 },	//3
	{ 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 3, 1, 0, 0, 0, 1 },	//4
	{ 1, 0, 1, 0, 0, 1, 0, 8, 1, 0, 0, 1, 0, 1, 0, 1 },	//5
	{ 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1 },	//6
	{ 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1 },	//7
	{ 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1 },	//8
	{ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1 },	//9
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1 },	//10
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }	//11
};

StageData g_stagedata;	//ゲーム本編のデータ

//ステージ初期化
void InitStage(){


DXライブラリーのサンプルも
https://dxlib.xsrv.jp/dxprogram.html#N3

コード:

// マップ表示基本
#include "DxLib.h"

#define MAP_SIZE	64			// マップチップ一つのドットサイズ

#define MAP_WIDTH	10			// マップの幅
#define MAP_HEIGHT	8			// マップの縦長さ

// マップのデータ
int MapData[ MAP_HEIGHT ][ MAP_WIDTH ] =
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 } ,
	{ 0, 1, 0, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 1, 0, 1, 1, 0, 0, 0, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0 } ,
	{ 0, 1, 0, 1, 0, 0, 0, 0, 1, 0 } ,
	{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } ,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } 
} ;

int コンマ・セパレートですね
ここにあるいろいろなサンプルを触ってみるのがいいでしょうね。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#9

投稿記事 by プログラマ見習い » 5年前

Mathさん。かずまさん。貴重なアドバイスありがとうごさいます。
「相当頭が混乱して様ですね。」
はい。おっしゃる通り、試行錯誤を続けているうちに、頭が疲労してしまいました。ソースコードに初歩的なミスがあるのも、そのためです。修正を繰り返しているうちに、気づかないうちにミスを犯した部分があります。
疲れに気を付けながら、またじっくり試行錯誤をするつもりです。

 私は当サイトの規約の趣旨を考慮しながら、どう説明すればいいか考えた上で慎重に言葉を選んで投稿したつもりでしたが、説明が不十分で、ソースコードに初歩的なミスがあるなど、不適切な部分がありました。お詫び申し上げます。


11、AAなど、2行になっているのは、扱うデータの種類が多くなった場合に備えての事です。

根本的な質問ですが、以下のようなメモ帳に書かれた00,00,11,11,11,00,11,AAなどのカンマで区切られた2行以上の文字列は、読み込んでマップデータに変換する事は,
そもそも技術的に可能なのでしょうか?

00,00,11,11,11,00,11,AA
00,AA,11,11,11,00,11,00
11,00,00,11,11,00,11,AA

もしも可能なのであれば、引き続き試行錯誤するつもりですが、不可能であれば、諦めます。

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

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#10

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

どう直せばいいかを考えるのは難しそうだったので、
とりあえず、コンマで区切ってデータを読み込む部分を作ってみました。
変換の方法は、何がしたいのかがわからないのでわかりません。
やりたいことやその実装に応じて適宜行ってください。
ただし、少なくとも、指摘されている通りchar型に複数の文字は
(使う文字の集合を決めて自分でエンコードするなどの工夫をしない限り)入りません。

コード:

#include <DxLib.h>
#include <cstdio>
#include <vector>
#include <string>

// 対応していない環境用
//#define sprintf_s snprintf

// データを読み込んで返す
std::vector<std::vector<std::string> > loadMapData(void) {
	std::vector<std::vector<std::string> > result;
	std::vector<std::string> rowBuffer;
	std::string cellBuffer;
	int fp;
	char fileName[1024];
	// ファイル名を用意する (拡張子が無いが、いいのかな?)
	sprintf_s(fileName, sizeof(fileName), "media/map%d", 1);
	// ファイルを開く
	fp = FileRead_open(fileName);
	if (fp == 0) {
		printfDx("ファイル読み込みエラー");
		return result;
	}
	// データを読み込む
	bool prevIsCr = false; // CRLFを二重にカウントするのを防ぐ用
	for (;;) {
		int c = FileRead_getc(fp);
		if (c < 0) break;
		if (c == '\r' || c == '\n') {
			if (!(prevIsCr && c == '\n')) { // CRLFを二重にカウントするのを防ぐ
				// セルのデータを行に反映させる
				rowBuffer.push_back(cellBuffer);
				// 行のデータを全体に反映させる
				result.push_back(rowBuffer);
				// データバッファを初期化する
				rowBuffer.clear();
				cellBuffer.clear();
			}
		} else if (c == ',') {
			// セルのデータを行に反映させる
			rowBuffer.push_back(cellBuffer);
			// データバッファを初期化する
			cellBuffer.clear();
		} else {
			// セルのデータに加える 
			cellBuffer.push_back(c);
		}
		// 改行の状態を更新する
		prevIsCr = (c == '\r');
	}
	// 最後の改行の後にデータがあったら反映させる
	if (!cellBuffer.empty() || !rowBuffer.empty()) {
		// セルのデータを行に反映させる
		rowBuffer.push_back(cellBuffer);
		// 行のデータを全体に反映させる
		result.push_back(rowBuffer);
	}
	// ファイルを閉じる
	FileRead_close(fp);
	// 読み込んだデータを返す
	return result;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
	if (ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() != 0) return -1;
	SetDrawScreen(DX_SCREEN_BACK);

	// マップデータを読み込む
	std::vector<std::vector<std::string> > mapData = loadMapData();
	// 読み込んだデータを出力する
	for (size_t i = 0; i < mapData.size(); i++) {
		printfDx("%2d:", i);
		for (size_t j = 0; j < mapData[i].size(); j++) {
			if (j > 0) {
				if (j % 20 == 0) printfDx("\n  ");
				printfDx(" ");
			}
			printfDx("%s", mapData[i][j].c_str());
		}
		printfDx("\n");
	}

	while (ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		ScreenFlip();
	}

	DxLib_End();
	return 0;
}
実行結果
ss20190723.png
実行結果
ss20190723.png (23.26 KiB) 閲覧数: 47398 回
プログラマ見習い さんが書きました:
5年前
根本的な質問ですが、以下のようなメモ帳に書かれた00,00,11,11,11,00,11,AAなどのカンマで区切られた2行以上の文字列は、読み込んでマップデータに変換する事は,
そもそも技術的に可能なのでしょうか?
可能と考えられます。
まず、変換先の「マップデータ」を定義するところから始めましょう。
添付ファイル
media.zip
マップデータ
(350 バイト) ダウンロード数: 497 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#11

投稿記事 by かずま » 5年前

プログラマ見習い さんが書きました:
5年前
11、AAなど、2行になっているのは、扱うデータの種類が多くなった場合に備えての事です。
何種類のデータが必要ですか?
必ず答えてください。
プログラマ見習い さんが書きました:
5年前
根本的な質問ですが、以下のようなメモ帳に書かれた00,00,11,11,11,00,11,AAなどのカンマで区切られた2行以上の文字列は、読み込んでマップデータに変換する事は,
そもそも技術的に可能なのでしょうか?
可能です。
00,01,02,...,0A,0B,0C,0D,0E,0F,10,11,12,...,FD,FE,FF
のように 16進で書けば、256種類のデータを扱えます。

media/map1

コード:

00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
00,00,00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
strtol を使い、0x11 や 0xAA として読み込みます。

コード:

#include <DxLib.h>

#define MAPSIZE 32

#define HEIGHT 15
#define WIDTH  40

#define CHARA (HEIGHT * WIDTH)

struct ImageData {
	int kabe01;
	int teki0A[2];
};

struct ImageData im;

struct CharaData {
	char kind;
	int anime_pattern;
	int x, y;
	int body;
};
int counter;

struct CharaData charadata[CHARA];
unsigned int g_anime_counter = 0;
char mapdata[HEIGHT][WIDTH];

void MapLoad()
{
	ZeroMemory(charadata, sizeof(charadata));

	char buf[1024];
	strcpy(buf, "media/map1");
	int fh = FileRead_open(buf);
	if (fh == NULL) { printfDx("ファイル読み込みエラー"); return; }

	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fh) == -1) break;
		char *p = buf;                          // ★
		for (int x = 0; x < WIDTH; x++) {       // ★
			mapdata[y][x] = strtol(p, &p, 16);  // ★
			p++; // skip ','                    // ★
		}                                       // ★
	}
	FileRead_close(fh);
}

void Load()
{
	im.kabe01 = LoadGraph("media/kabe01.bmp");
	LoadDivGraph("media/teki0A.bmp", 2, 2, 1, 32, 32, im.teki0A);
}

void Init()
{
	counter = 0;
	for (int y = 0; y < HEIGHT; y++) {
		for (int x = 0; x < WIDTH; x++) {
			unsigned char c = mapdata[y][x];  // ★
			charadata[counter].kind = c;
			charadata[counter].x = x * MAPSIZE;
			charadata[counter].y = y * MAPSIZE;
			switch (c) {
			case 0x11:  // ★
				charadata[counter].body = 1;
				mapdata[y][x] = '0';
				counter++;
				break;
			case 0xAA:  // ★
				charadata[counter].anime_pattern = 2;
				charadata[counter].body = 1;
				mapdata[y][x] = '0';
				counter++;
				break;
			}
		}
	}
}

void Move()
{
	for (int i = 0; i < counter; i++) {
		unsigned char c = charadata[i].kind;  // ★
		switch (c) {
		case 0x11:  // ★
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
			break;

		case 0xAA:  // ★
			int a = g_anime_counter / 20 % charadata[i].anime_pattern;
			DrawGraph(charadata[i].x, charadata[i].y, im.teki0A[a], TRUE);
			break;
		}
		charadata[i].x = charadata[i].x - 1;
	}
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
	if (ChangeWindowMode(TRUE) != 0) return -1;
	if (DxLib_Init() != 0) return -1;
	if (SetDrawScreen(DX_SCREEN_BACK) != 0) return -1;

	MapLoad();
	Load();
	Init();

	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		if (ClearDrawScreen() != 0) return -1;
		Move();
		g_anime_counter++;
		if (ScreenFlip() != 0) return -1;
	}

	if (DxLib_End() != 0) return -1;
	return 0;
}
このプログラムを実行した結果を報告してください。
また、プログラム上の疑問点を質問してください。

box
記事: 2002
登録日時: 14年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#12

投稿記事 by box » 5年前

ソースコードを書き直す際に書き間違えただけです。手書きでソースコードを書けば
投稿のためにわざわざ入力し直したんですか?うわ~そりゃ大変だ。
それは大変な手間がかかり、今回のように打ち間違えたコードを
アップしてしまうことになりかねませんので、コピペといういちばん楽と思われる
方法を使いましょう。
ソースコードが1万行くらいあっても手で打ち直しますか?ということです。
そんなことしたくありませんよね。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

アバター
usao
記事: 1889
登録日時: 11年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#13

投稿記事 by usao » 5年前

オフトピック
こんな単純データだったら,stringstream様のお力で解決してもらえば楽なのでは.

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#14

投稿記事 by プログラマ見習い » 5年前

皆さん。貴重なアドバイスありがとうございます。

まずはみけCATさん。みけCATさんが投稿してくれたソースコードをこちらでコンパイルしたら、正常に作動しました。

次にかずまさん。かずまさんが投稿してくれたソースコードををこちらでコンパイルしたら、エラー警告C4996が出て、strcpyに問題があると言う事でしたので、strcpyをsprintf_sに修正してコンパイルした所、真黒な画面が出ました。

次にboxさん。多分ソースコードの見直しのつもりで書き直しなんてしたんだと思いますが、かえって仇となりました。気をつけます。

次にusaoさん。stringstream様のお力を使いこなせれるように、試行錯誤中です。

現在皆様のアドバイスを参考に、試行錯誤中ですが、今の自分の実力では一筋縄ではいかない事が分かりました。

ただ、第一に、質問者である自分が何をしたいのか分からない、第二に、他人に期待しすぎていると言うご指摘があったので、それについて述べさせてもらいます。

第一については、もう一度分かりやすいように整理してから報告します。
第二については、客観的に見れば、おっしゃる通りだったと答えます。ただ、他の人にとっては簡単なプログラムでも、今の自分にとっては難しい事であることは確かです。

アバター
usao
記事: 1889
登録日時: 11年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#15

投稿記事 by usao » 5年前

オフトピック
カンマ区切りな内容のファイルを用意するとしたら,それを読込むプログラムの側ではカンマの存在に対処する必要がある.
その処理が自分自身に厳しいかどうかは,やる前にわかるハズ.

にも関わらず,何故カンマ区切りなフォーマットのデータファイルを用いようと思うのか.
わざわざ問題の難易度を自分自身で大きく引き上げて困っているという構図.
「自分が余裕で扱える形でデータを用意しちゃいけない縛り」みたいな営みなのか? 行き詰るのが好きなのか?

アバター
usao
記事: 1889
登録日時: 11年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#16

投稿記事 by usao » 5年前

オフトピック
> mapdataを二次元配列から一次元配列にする方法も試しました

こういうことしている時点で,何かが根本的にズレている気がする.

あるロジックがあるデータ構造を用いて動く状態が存在していて,
→当該データ構造のデータを用意する手段として「ファイルから読む」

じゃないのか?
データ構造側をファイル読込処理の都合によって変えちゃうの?

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#17

投稿記事 by プログラマ見習い » 5年前

 質問者である自分が何をしたいについて改めて説明しなおします。
 まずはmap0.txtの中身と、ソースコードを投稿します。
 今回はちゃんとコピペしたので、画面が正常に表示されるはずです。

 map0.txt

コード:

 
0000000000111111111100000000001111111111
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000AAA000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000AAA000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000111111111100000000001111111111
 


 map0.txtを読み込んだもの

コード:

 

#include <DxLib.h>

#define MAPSIZE 32 //マップサイズを決めます。

#define HEIGHT 15 //Y座標の最大値を決めます
#define WIDTH 40 //X座標の最大値を決めます

 //キャラクターの数の最大値を決めます。念のために多めにします。今回はマップデータの数に合わせます。
#define CHARA HEIGHT*WIDTH



 //画像データの構造体を作ります。
 //画像データは無理に配列やポインタで整理しようとすると、エラーやフリーズの原因になります。
struct ImageData{

 int kabe01; //
 int teki0A[2]; //

};

struct ImageData im; //



 //各キャラクターのデータの構造体を作ります。
struct CharaData{

 //int *ghandle; //アニメーションさせるために画像データハンドル。
 //ポインタ設定をしたが、これが原因の一つでした。

 char kind; //キャラクターの種類を格納。
 int anime_pattern; //アニメパーン数
 float x; //座標はfloatにします。
 float y;
 int body; //体力

};

struct CharaData charadata[CHARA]; //今回はcharadataと名づけます。
 //キャラクターは複数出現させるので、配列内に各キャラクターの最大値CHMAXを格納します。

//struct CharaData im[2]; //画像を描画するための変数。
//or//struct CharaData im[CHARA]; //画像を描画するための変数。



 //アニメーションカウンター用の変数を作ります。
unsigned int g_anime_counter=0;



 //マップデータを作ります。
char mapdata[HEIGHT][WIDTH];



  //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d.txt",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp=FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp==NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }



/////////////////////////////ここから////////////////////////////



 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){



  FileRead_scanf(fp,"%s",mapdata[y][x]);



 } //for(int x=0;x<WIDTH;x++)の最後

} //for(int y=0;y<HEIGHT;y++)の最後

/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後



 //画像をロードする関数を作ります。
void Load(){

 im.kabe01=LoadGraph("media/kabe01.jpg");

 LoadDivGraph("media/teki0A.jpg",2,2,1,32,32,im.teki0A);

}



 //初期化用の関数を作ります。
void Init(){

  //キャラクターをカウントする変数を作ります。必要な変数の一つです。
  //キャラクターをカウントする変数はローカル変数でも問題ありませんでした。
 int counter=0;

 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){

  char c=mapdata[y][x];

   //初期化してマップデータから、キャラクターのデータを取り出します。

   //kindにマップデータを代入します。
   //これも必要な変数の一つです。
  charadata[counter].kind=c;

  charadata[counter].x=(float)x*MAPSIZE;
  charadata[counter].y=(float)y*MAPSIZE;

  int charaValid=0;
   //この変数を利用しないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   //Validは英語で「有効、根拠の確実な、確かな、正当な」などの意味です。

   //キャラクターごとに異なるものはswicth文を使います。
  switch(c){ //なお、ここにcounterを入れてしまうと、フリーズしてしまいました。
   case '1':
    charadata[counter].body=1;
    charaValid=1; //case毎にcv=1;と代入します。
    break;

   case 'A':
    charadata[counter].anime_pattern=2; //アニメーションさせる場合はここで代入します。
    charadata[counter].body=1;
    charaValid=1; //
    break;

  }

    //このif文がないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   if(charaValid){
   mapdata[y][x]='0'; //マップデータを'0'にする事で、データの取り出しは終わりです。
    //ここでキャラクターの数を一つずつ増やしていきます。
   counter++;
   }

  }
 }

}


 //描画と移動処理用の関数を作ります
void Move(){

 for(int i=0;i<CHARA;i++){

  char c=charadata[i].kind;

  switch(c){
   //ここにcharadata[i].kindではなくiを入れると、一つしか描画されませんでした。
   //また、フリーズしてまった場合もあります。

   case '1':
    DrawGraph(charadata[i].x,charadata[i].y,im.kabe01,TRUE);
  
    break;

   case 'A':
    int a=g_anime_counter/20%charadata[i].anime_pattern;
    DrawGraph(charadata[i].x,charadata[i].y,im.teki0A[a],TRUE);

    break;

  }

   //キャラクター単位で動かす方法でマップスクロールを行います。
  charadata[i].x=charadata[i].x-1;

 }

}



 //WinMain関数の中に、先ほど作った関数を入れます。//Move();だけwhile内に入れます。
int WINAPI WinMain(HINSTANCE hI,HINSTANCE hP,LPSTR lpC,int nC){

 if(ChangeWindowMode(TRUE)!=0) return -1; //ウィンドウモードの変更
 if(DxLib_Init()!=0) return -1; //DXライブラリ初期化処理
 if(SetDrawScreen(DX_SCREEN_BACK)!=0) return -1; //描画先を裏画面に設定


 //ロードの関数は、ここではここに入れます。


 MapLoad(); //マップデータのロード

 Load(); //画像のロード 

 Init(); //初期化。//if(charaValid)に関するコードを書いていない時は、ここに置かないで、while文の中に置くと、適切に描画されません。



 while(ProcessMessage()==0&&CheckHitKey(KEY_INPUT_ESCAPE)==0){
  //メッセージ処理(XキーかAlt+F4キーが押されたら終了)
  //ESCキーが押されたら終了
 if(ClearDrawScreen()!=0) return -1; //裏画面を消す


  //Init(); //初期化。//if(charaValid)に関するコードを書いていないでwhile文の中に初期化関数Init();置くと、適切に描画されません。
   //この関数をそのままwhile文の中に入れてしまうと、一番最初の画像が消えてしまう。

  Move(); //画像の描画と移動用の関数をここに置きます。

  g_anime_counter++; //



  if(ScreenFlip()!=0) return -1; //裏画面を表画面に反映

 }

 if(DxLib_End()!=0) return -1; //DXライブラリの終了処理
 return 0; //ソフトの終了

}

 


 次にvoid MapLoad(){}の中身をご覧ください。
 以上のソースコードは、map0.txtからデータを読み込んで、マップデータに変換しているのですが、map0.txtは、ご覧の通り、カンマや空白などで区切られておらず、1ケタずつ読み込まれます。

 以上の方法には、二つ問題があります。
 第一に、以上のような1ケタずつ読み込んでいく方法だと、整数10個、アルファベット大文字26文字、小文字26文字で、合計62種類までのデータを読み込む事が出来ます。
 しかし、もしも62種類よりも多くのデータを読み込みたい場合、2ケタの整数や文字を用意する必要があります。例えば100種類、200種類のデータを読み込みたい場合、00、01、AAなどのような整数や文字が必要であります、

 第二に、カンマや空白などで区切られていないと、何行目の何列目かが分かり辛い、目で見ると目が痛くなってしまうと言う問題があります。そこで、カンマや空白などでデータを区切る事で、見えやすくする必要があります。

 以上の理由から、私はカンマ区切りの文字を読み込む事と、2ケタの文字を読み込む事がしたいのです。



 次に、2ケタずつカンマで区切って読み込んだソースコードを投稿します。
 但し、ここではmap0.txtをmap1.txtに、void Init(){}とvoid Move(){}関数の中身の1とAを、それぞれ1とAに変更しただけです。

 map1.txt

コード:

 
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
 


 map1.txtを読み込んだもの

コード:

 
#include <DxLib.h>

#define MAPSIZE 32 //マップサイズを決めます。

#define HEIGHT 15 //Y座標の最大値を決めます
#define WIDTH 40 //X座標の最大値を決めます

 //キャラクターの数の最大値を決めます。念のために多めにします。今回はマップデータの数に合わせます。
#define CHARA HEIGHT*WIDTH



 //画像データの構造体を作ります。
 //画像データは無理に配列やポインタで整理しようとすると、エラーやフリーズの原因になります。
struct ImageData{

 int kabe01; //
 int teki0A[2]; //

};

struct ImageData im; //



 //各キャラクターのデータの構造体を作ります。
struct CharaData{

 //int *ghandle; //アニメーションさせるために画像データハンドル。
 //ポインタ設定をしたが、これが原因の一つでした。

 char kind; //キャラクターの種類を格納。
 int anime_pattern; //アニメパーン数
 float x; //座標はfloatにします。
 float y;
 int body; //体力

};

struct CharaData charadata[CHARA]; //今回はcharadataと名づけます。
 //キャラクターは複数出現させるので、配列内に各キャラクターの最大値CHMAXを格納します。

//struct CharaData im[2]; //画像を描画するための変数。
//or//struct CharaData im[CHARA]; //画像を描画するための変数。



 //アニメーションカウンター用の変数を作ります。
unsigned int g_anime_counter=0;



 //マップデータを作ります。
char mapdata[HEIGHT][WIDTH];



  //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d.txt",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp=FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp==NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }



/////////////////////////////ここから////////////////////////////



 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){



  FileRead_scanf(fp,"%s",mapdata[y][x]);



 } //for(int x=0;x<WIDTH;x++)の最後

} //for(int y=0;y<HEIGHT;y++)の最後

/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後



 //画像をロードする関数を作ります。
void Load(){

 im.kabe01=LoadGraph("media/kabe01.jpg");

 LoadDivGraph("media/teki0A.jpg",2,2,1,32,32,im.teki0A);

}



 //初期化用の関数を作ります。
void Init(){

  //キャラクターをカウントする変数を作ります。必要な変数の一つです。
  //キャラクターをカウントする変数はローカル変数でも問題ありませんでした。
 int counter=0;

 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){

  char c=mapdata[y][x];

   //初期化してマップデータから、キャラクターのデータを取り出します。

   //kindにマップデータを代入します。
   //これも必要な変数の一つです。
  charadata[counter].kind=c;

  charadata[counter].x=(float)x*MAPSIZE;
  charadata[counter].y=(float)y*MAPSIZE;

  int charaValid=0;
   //この変数を利用しないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   //Validは英語で「有効、根拠の確実な、確かな、正当な」などの意味です。

   //キャラクターごとに異なるものはswicth文を使います。
  switch(c){ //なお、ここにcounterを入れてしまうと、フリーズしてしまいました。
   case '11':
    charadata[counter].body=1;
    charaValid=1; //case毎にcv=1;と代入します。
    break;

   case 'AA':
    charadata[counter].anime_pattern=2; //アニメーションさせる場合はここで代入します。
    charadata[counter].body=1;
    charaValid=1; //
    break;

  }

    //このif文がないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   if(charaValid){
   mapdata[y][x]='0'; //マップデータを'0'にする事で、データの取り出しは終わりです。
    //ここでキャラクターの数を一つずつ増やしていきます。
   counter++;
   }

  }
 }

}


 //描画と移動処理用の関数を作ります
void Move(){

 for(int i=0;i<CHARA;i++){

  char c=charadata[i].kind;

  switch(c){
   //ここにcharadata[i].kindではなくiを入れると、一つしか描画されませんでした。
   //また、フリーズしてまった場合もあります。

   case '11':
    DrawGraph(charadata[i].x,charadata[i].y,im.kabe01,TRUE);
  
    break;

   case 'AA':
    int a=g_anime_counter/20%charadata[i].anime_pattern;
    DrawGraph(charadata[i].x,charadata[i].y,im.teki0A[a],TRUE);

    break;

  }

   //キャラクター単位で動かす方法でマップスクロールを行います。
  charadata[i].x=charadata[i].x-1;

 }

}



 //WinMain関数の中に、先ほど作った関数を入れます。//Move();だけwhile内に入れます。
int WINAPI WinMain(HINSTANCE hI,HINSTANCE hP,LPSTR lpC,int nC){

 if(ChangeWindowMode(TRUE)!=0) return -1; //ウィンドウモードの変更
 if(DxLib_Init()!=0) return -1; //DXライブラリ初期化処理
 if(SetDrawScreen(DX_SCREEN_BACK)!=0) return -1; //描画先を裏画面に設定


 //ロードの関数は、ここではここに入れます。


 MapLoad(); //マップデータのロード

 Load(); //画像のロード 

 Init(); //初期化。//if(charaValid)に関するコードを書いていない時は、ここに置かないで、while文の中に置くと、適切に描画されません。



 while(ProcessMessage()==0&&CheckHitKey(KEY_INPUT_ESCAPE)==0){
  //メッセージ処理(XキーかAlt+F4キーが押されたら終了)
  //ESCキーが押されたら終了
 if(ClearDrawScreen()!=0) return -1; //裏画面を消す


  //Init(); //初期化。//if(charaValid)に関するコードを書いていないでwhile文の中に初期化関数Init();置くと、適切に描画されません。
   //この関数をそのままwhile文の中に入れてしまうと、一番最初の画像が消えてしまう。

  Move(); //画像の描画と移動用の関数をここに置きます。

  g_anime_counter++; //



  if(ScreenFlip()!=0) return -1; //裏画面を表画面に反映

 }

 if(DxLib_End()!=0) return -1; //DXライブラリの終了処理
 return 0; //ソフトの終了

}
 


 以上のソースコードをコンパイルすると、真黒な画面が表示されるだけです。

 修正するべき箇所は、void MapLoad(){}関数内の//ここから//、//ここまで//の間に囲まれている部分である事までは分かっているのですが、どのように修正すればよいかが解決出来ていないと言うのが現状です。

以下にvoid MapLoad{}を抜粋します。

コード:

 
  //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d.txt",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp=FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp==NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }



/////////////////////////////ここから////////////////////////////



 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){



  FileRead_scanf(fp,"%s",mapdata[y][x]);



 } //for(int x=0;x<WIDTH;x++)の最後

} //for(int y=0;y<HEIGHT;y++)の最後

/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後


 

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#18

投稿記事 by プログラマ見習い » 5年前

コピペする投稿するソースコードを間違えました。上記のソースコードは忘れて下さい。
改めて説明しなおします。

 質問者である自分が何をしたいについて改めて説明しなおします。

 まずはmap0.txtの中身と、ソースコードを投稿します。
 今回はちゃんとコピペしたので、今度こそ画面が正常に表示されるはずです。

 map0.txt

コード:

 
0000000000111111111100000000001111111111
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000AAA000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000AAA000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000111111111100000000001111111111
 

 map1.txtを読み込んだもの

コード:

  
#include <DxLib.h>



#define MAPSIZE 32 //マップサイズを決めます。

#define HEIGHT 15 //Y座標の最大値を決めます
#define WIDTH 40 //X座標の最大値を決めます

 //キャラクターの数の最大値を決めます。念のために多めにします。今回はマップデータの数に合わせます。
#define CHARA HEIGHT*WIDTH



 //画像データの構造体を作ります。
 //画像データは無理に配列やポインタで整理しようとすると、エラーやフリーズの原因になります。
struct ImageData{

 int kabe01; //
 int teki0A[2]; //

};

struct ImageData im; //



 //各キャラクターのデータの構造体を作ります。
struct CharaData{

 //int *ghandle; //アニメーションさせるために画像データハンドル。
 //ポインタ設定をしたが、これが原因の一つでした。

 char kind; //キャラクターの種類を格納。
 int anime_pattern; //アニメパーン数
 float x; //座標はfloatにします。
 float y;
 int body; //体力

};

struct CharaData charadata[CHARA]; //今回はcharadataと名づけます。
 //キャラクターは複数出現させるので、配列内に各キャラクターの最大値CHMAXを格納します。

//struct CharaData im[2]; //画像を描画するための変数。
//or//struct CharaData im[CHARA]; //画像を描画するための変数。



 //アニメーションカウンター用の変数を作ります。
unsigned int g_anime_counter=0;



 //マップデータを作ります。
char mapdata[HEIGHT][WIDTH];



  //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d.txt",0); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp=FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp==NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }



/////////////////////////////ここから////////////////////////////


 for(int y=0;y<HEIGHT;y++){

  //1024が1023に減っているのは、NULL文字対策
 FileRead_gets(buf,1023,fp); //ファイルを一行読み込む



  for(int x=0;x<WIDTH;x++){

   mapdata[y][x]=buf[x];

 } //for(int x=0;x<WIDTH;x++)の最後

} //for(int y=0;y<HEIGHT;y++)の最後

/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後



 //画像をロードする関数を作ります。
void Load(){

 im.kabe01=LoadGraph("media/kabe01.jpg");

 LoadDivGraph("media/teki0A.jpg",2,2,1,32,32,im.teki0A);

}



 //初期化用の関数を作ります。
void Init(){

  //キャラクターをカウントする変数を作ります。必要な変数の一つです。
  //キャラクターをカウントする変数はローカル変数でも問題ありませんでした。
 int counter=0;

 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){

  char c=mapdata[y][x];

   //初期化してマップデータから、キャラクターのデータを取り出します。

   //kindにマップデータを代入します。
   //これも必要な変数の一つです。
  charadata[counter].kind=c;

  charadata[counter].x=(float)x*MAPSIZE;
  charadata[counter].y=(float)y*MAPSIZE;

  int charaValid=0;
   //この変数を利用しないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   //Validは英語で「有効、根拠の確実な、確かな、正当な」などの意味です。

   //キャラクターごとに異なるものはswicth文を使います。
  switch(c){ //なお、ここにcounterを入れてしまうと、フリーズしてしまいました。
   case '1':
    charadata[counter].body=1;
    charaValid=1; //case毎にcv=1;と代入します。
    break;

   case 'A':
    charadata[counter].anime_pattern=2; //アニメーションさせる場合はここで代入します。
    charadata[counter].body=1;
    charaValid=1; //
    break;

  }

    //このif文がないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   if(charaValid){
   mapdata[y][x]='0'; //マップデータを'0'にする事で、データの取り出しは終わりです。
    //ここでキャラクターの数を一つずつ増やしていきます。
   counter++;
   }

  }
 }

}


 //描画と移動処理用の関数を作ります
void Move(){

 for(int i=0;i<CHARA;i++){

  char c=charadata[i].kind;

  switch(c){
   //ここにcharadata[i].kindではなくiを入れると、一つしか描画されませんでした。
   //また、フリーズしてまった場合もあります。

   case '1':
    DrawGraph(charadata[i].x,charadata[i].y,im.kabe01,TRUE);
  
    break;

   case 'A':
    int a=g_anime_counter/20%charadata[i].anime_pattern;
    DrawGraph(charadata[i].x,charadata[i].y,im.teki0A[a],TRUE);

    break;

  }

   //キャラクター単位で動かす方法でマップスクロールを行います。
  charadata[i].x=charadata[i].x-1;

 }

}



 //WinMain関数の中に、先ほど作った関数を入れます。//Move();だけwhile内に入れます。
int WINAPI WinMain(HINSTANCE hI,HINSTANCE hP,LPSTR lpC,int nC){

 if(ChangeWindowMode(TRUE)!=0) return -1; //ウィンドウモードの変更
 if(DxLib_Init()!=0) return -1; //DXライブラリ初期化処理
 if(SetDrawScreen(DX_SCREEN_BACK)!=0) return -1; //描画先を裏画面に設定


 //ロードの関数は、ここではここに入れます。


 MapLoad(); //マップデータのロード

 Load(); //画像のロード 

 Init(); //初期化。//if(charaValid)に関するコードを書いていない時は、ここに置かないで、while文の中に置くと、適切に描画されません。



 while(ProcessMessage()==0&&CheckHitKey(KEY_INPUT_ESCAPE)==0){
  //メッセージ処理(XキーかAlt+F4キーが押されたら終了)
  //ESCキーが押されたら終了
 if(ClearDrawScreen()!=0) return -1; //裏画面を消す


  //Init(); //初期化。//if(charaValid)に関するコードを書いていないでwhile文の中に初期化関数Init();置くと、適切に描画されません。
   //この関数をそのままwhile文の中に入れてしまうと、一番最初の画像が消えてしまう。

  Move(); //画像の描画と移動用の関数をここに置きます。

  g_anime_counter++; //



  if(ScreenFlip()!=0) return -1; //裏画面を表画面に反映

 }

 if(DxLib_End()!=0) return -1; //DXライブラリの終了処理
 return 0; //ソフトの終了

}
 次にvoid MapLoad(){}の中身をご覧ください。
 以上のソースコードは、map0.txtからデータを読み込んで、マップデータに変換しているのですが、map0.txtは、ご覧の通り、カンマや空白などで区切られておらず、1ケタずつ読み込まれます。

 以上の方法には、二つ問題があります。
 第一に、以上のような1ケタずつ読み込んでいく方法だと、整数10個、アルファベット大文字26文字、小文字26文字で、合計62種類までのデータを読み込む事が出来ます。
 しかし、もしも62種類よりも多くのデータを読み込みたい場合、2ケタの整数や文字を用意する必要があります。例えば100種類、200種類のデータを読み込みたい場合、00、01、AAなどのような整数や文字が必要であります、

 第二に、カンマや空白などで区切られていないと、何行目の何列目かが分かり辛い、目で見ると目が痛くなってしまうと言う問題があります。そこで、カンマや空白などでデータを区切る事で、見えやすくする必要があります。

 以上の理由から、私はカンマ区切りの文字を読み込む事と、2ケタの文字を読み込む事がしたいのです。



 次に、2ケタずつカンマで区切って読み込んだソースコードを投稿します。
 但し、ここではmap0.txtをmap1.txtに、void Init(){}とvoid Move(){}関数の中身の1とAを、それぞれ1とAに変更しただけです。
 map1.txt

コード:

 

00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
 




 map1.txtを読み込んだもの

コード:

 

#include <DxLib.h>



#define MAPSIZE 32 //マップサイズを決めます。

#define HEIGHT 15 //Y座標の最大値を決めます
#define WIDTH 40 //X座標の最大値を決めます

 //キャラクターの数の最大値を決めます。念のために多めにします。今回はマップデータの数に合わせます。
#define CHARA HEIGHT*WIDTH



 //画像データの構造体を作ります。
 //画像データは無理に配列やポインタで整理しようとすると、エラーやフリーズの原因になります。
struct ImageData{

 int kabe01; //
 int teki0A[2]; //

};

struct ImageData im; //



 //各キャラクターのデータの構造体を作ります。
struct CharaData{

 //int *ghandle; //アニメーションさせるために画像データハンドル。
 //ポインタ設定をしたが、これが原因の一つでした。

 char kind; //キャラクターの種類を格納。
 int anime_pattern; //アニメパーン数
 float x; //座標はfloatにします。
 float y;
 int body; //体力

};

struct CharaData charadata[CHARA]; //今回はcharadataと名づけます。
 //キャラクターは複数出現させるので、配列内に各キャラクターの最大値CHMAXを格納します。

//struct CharaData im[2]; //画像を描画するための変数。
//or//struct CharaData im[CHARA]; //画像を描画するための変数。



 //アニメーションカウンター用の変数を作ります。
unsigned int g_anime_counter=0;



 //マップデータを作ります。
char mapdata[HEIGHT][WIDTH];



  //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d.txt",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp=FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp==NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }



/////////////////////////////ここから////////////////////////////


 for(int y=0;y<HEIGHT;y++){

  //1024が1023に減っているのは、NULL文字対策
 FileRead_gets(buf,1023,fp); //ファイルを一行読み込む



  for(int x=0;x<WIDTH;x++){

   mapdata[y][x]=buf[x];

 } //for(int x=0;x<WIDTH;x++)の最後

} //for(int y=0;y<HEIGHT;y++)の最後

/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後



 //画像をロードする関数を作ります。
void Load(){

 im.kabe01=LoadGraph("media/kabe01.jpg");

 LoadDivGraph("media/teki0A.jpg",2,2,1,32,32,im.teki0A);

}



 //初期化用の関数を作ります。
void Init(){

  //キャラクターをカウントする変数を作ります。必要な変数の一つです。
  //キャラクターをカウントする変数はローカル変数でも問題ありませんでした。
 int counter=0;

 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){

  char c=mapdata[y][x];

   //初期化してマップデータから、キャラクターのデータを取り出します。

   //kindにマップデータを代入します。
   //これも必要な変数の一つです。
  charadata[counter].kind=c;

  charadata[counter].x=(float)x*MAPSIZE;
  charadata[counter].y=(float)y*MAPSIZE;

  int charaValid=0;
   //この変数を利用しないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   //Validは英語で「有効、根拠の確実な、確かな、正当な」などの意味です。

   //キャラクターごとに異なるものはswicth文を使います。
  switch(c){ //なお、ここにcounterを入れてしまうと、フリーズしてしまいました。
   case '11':
    charadata[counter].body=1;
    charaValid=1; //case毎にcv=1;と代入します。
    break;

   case 'AA':
    charadata[counter].anime_pattern=2; //アニメーションさせる場合はここで代入します。
    charadata[counter].body=1;
    charaValid=1; //
    break;

  }

    //このif文がないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   if(charaValid){
   mapdata[y][x]='0'; //マップデータを'0'にする事で、データの取り出しは終わりです。
    //ここでキャラクターの数を一つずつ増やしていきます。
   counter++;
   }

  }
 }

}


 //描画と移動処理用の関数を作ります
void Move(){

 for(int i=0;i<CHARA;i++){

  char c=charadata[i].kind;

  switch(c){
   //ここにcharadata[i].kindではなくiを入れると、一つしか描画されませんでした。
   //また、フリーズしてまった場合もあります。

   case '11':
    DrawGraph(charadata[i].x,charadata[i].y,im.kabe01,TRUE);
  
    break;

   case 'AA':
    int a=g_anime_counter/20%charadata[i].anime_pattern;
    DrawGraph(charadata[i].x,charadata[i].y,im.teki0A[a],TRUE);

    break;

  }

   //キャラクター単位で動かす方法でマップスクロールを行います。
  charadata[i].x=charadata[i].x-1;

 }

}



 //WinMain関数の中に、先ほど作った関数を入れます。//Move();だけwhile内に入れます。
int WINAPI WinMain(HINSTANCE hI,HINSTANCE hP,LPSTR lpC,int nC){

 if(ChangeWindowMode(TRUE)!=0) return -1; //ウィンドウモードの変更
 if(DxLib_Init()!=0) return -1; //DXライブラリ初期化処理
 if(SetDrawScreen(DX_SCREEN_BACK)!=0) return -1; //描画先を裏画面に設定


 //ロードの関数は、ここではここに入れます。


 MapLoad(); //マップデータのロード

 Load(); //画像のロード 

 Init(); //初期化。//if(charaValid)に関するコードを書いていない時は、ここに置かないで、while文の中に置くと、適切に描画されません。



 while(ProcessMessage()==0&&CheckHitKey(KEY_INPUT_ESCAPE)==0){
  //メッセージ処理(XキーかAlt+F4キーが押されたら終了)
  //ESCキーが押されたら終了
 if(ClearDrawScreen()!=0) return -1; //裏画面を消す


  //Init(); //初期化。//if(charaValid)に関するコードを書いていないでwhile文の中に初期化関数Init();置くと、適切に描画されません。
   //この関数をそのままwhile文の中に入れてしまうと、一番最初の画像が消えてしまう。

  Move(); //画像の描画と移動用の関数をここに置きます。

  g_anime_counter++; //



  if(ScreenFlip()!=0) return -1; //裏画面を表画面に反映

 }

 if(DxLib_End()!=0) return -1; //DXライブラリの終了処理
 return 0; //ソフトの終了

}
 


 以上のソースコードをコンパイルすると、真黒な画面が表示されるだけです。

 修正するべき箇所は、void MapLoad(){}関数内の//ここから//、//ここまで//の間に囲まれている部分である事までは分かっているのですが、どのように修正すればよいかが解決出来ていないと言うのが現状です。

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#19

投稿記事 by かずま » 5年前

プログラマ見習い さんが書きました:
5年前
 修正するべき箇所は、void MapLoad(){}関数内の//ここから//、//ここまで//の間に囲まれている部分である事までは分かっているのですが、どのように修正すればよいかが解決出来ていないと言うのが現状です。
#11 のプログラムは読んでいないのですね。
strcpy を sprintf_s に修正したら真黒な画面が出ました、で終わりですか?
真黒になったのは、そのプログラムが #1 の最初のプログラムにあったように
.jpg ではなく .bmp の画像ファイルになっていたからだと思います。
真黒の画面になったら、それで終わりですか?
プログラムを読もうとしないのですか?
// ★ を付けて目立つようにしたのに。

もう一度、修正個所を示します。

コード:

/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		char *p = buf;
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = strtol(p, &p, 16);
			p++; // skip ','
		}
	}
/////////////////////////////ここまで////////////////////////////
さらに次の変更が必要です。

コード:

char c=mapdata[y][x]; を unsigned char c = mapdata[y][x]; に変更

char c=charadata[i].kind; を unsigned char c = charadata[i].kind; に変更

case '11': を case 0x11: に変更(2個所)

case 'AA': を case 0xAA: に変更(2個所)
疑問点があれば、具体的に質問してください

アバター
かめのこのこのこ
記事: 15
登録日時: 7年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#20

投稿記事 by かめのこのこのこ » 5年前

いまいちやりたいことをうまく把握できないので、こちらからお尋ねしますが..

マップテキスト map1.txt がありましたとさ

コード:

 

00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
 
その(データのある)1行目に注目しましたとさ

コード:

00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
それのコンマを無視して読み込みたいのさ (1: カンマ区切りの文字を読み込む事 or カンマを読み込まないで読み込みたい文字列だけを読み込む)

コード:

00000000000000000000111111111111111111110000000000000000000011111111111111111111
最後にこれを2文字(2桁)ずつ区切ってマップデータを入れる変数に保存したいのさ (2: 2ケタの文字を読み込む事 or 00,11,AAなど、一組の文字列として読み込む)

mapdata[0][0]mapdata[0][1]mapdata[0][2]...
'00''00''00'...
という把握でよろしいでしょうか。

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

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#21

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

このようなコードを書いてみました。
strchrおよびstrcmpを使うために、

コード:

#include <DxLib.h>
の後ろに

コード:

#include <cstring>
を追加してください。

コード:

  //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d.txt",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp=FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp==NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }



/////////////////////////////ここから////////////////////////////



 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){



  // これは文字列の読み込み先として無効な可能性が高いポインタを指定することになるのでダメ
  //FileRead_scanf(fp,"%s",mapdata[y][x]);
  // 1セル分のデータを読み込む場所を作る
  char input[1024], *cr;
  // 1セル分のデータを読み込む
  FileRead_scanf(fp,"%1023[^\n,]%*c",input);
  // ゴミが付いている場合があるので、外す
  if ((cr = strchr(input, '\r')) != NULL) *cr = '\0';
  // データを変換する
  if (strcmp(input, "00") == 0) mapdata[y][x] = 0;
  else if (strcmp(input, "11") == 0) mapdata[y][x] = '11';
  else if (strcmp(input, "AA") == 0) mapdata[y][x] = 'AA';
  else x--; // 変換できなかった場合、なかったことにする



 } //for(int x=0;x<WIDTH;x++)の最後

} //for(int y=0;y<HEIGHT;y++)の最後

/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後
複数文字の文字定数がどのような値になるかは、処理系定義です。
GCC 4.8.1では動きませんでしたが、MathさんのいうVS2019なら動くかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#22

投稿記事 by プログラマ見習い » 5年前

まずはかずまさん。
申し訳ございません。
報告して下さいと書かれていたので、皆さんに急いで報告しなければならないと思い、結果としてあのような報告となってしまいました。
ソースコードは読んでいたのですが、画像ファイル形式を完全に見落としてしまいました。後で読み返して間違いに気づいたので、修正したら正常に描画されました。
不快な思いをさせて申し訳ございませんでした。

そして皆さん。
皆さんのアドバイスを読んで、書籍やネットで調べて、考えている所です。
次の返答までに時間がかかりますが、どうかご容赦下さい。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#23

投稿記事 by プログラマ見習い » 5年前

かめのこのこのこさん。
はい。その通りです。
mapdata[0][0]="00";
mapdata[0][1]="00";
mapdata[0][2]="00";
mapdata[0][?]="11"
~~~~~~省略
mapdata[?][?]="AA";
~~~~~~省略
この把握で宜しいです。

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#24

投稿記事 by かずま » 5年前

プログラマ見習い さんが書きました:
5年前
不快な思いをさせて申し訳ございませんでした。
不快には思いませんが、
#7 さんが書きました: media/map1 ですが、提示されたものは、空行 2行、データ 11行、空行 3行
になっていますよ。いいんですか?
なぜ、この質問にすぐ答えてくれないのですか?
未だに、先頭に空行を含むデータを提示していますよね。
空行があると正しく読めません。
#7 さんが書きました:char の変数に入らない '11' や 'AA' などのデータを使わず、
'0'、'1'、'A' にしました。
char の変数に入らないと言っているのに、まだ '11' を使おうとしていますね。
なぜ入らないのか調べて分からなければ、それを質問してください。
#11 さんが書きました:何種類のデータが必要ですか? 必ず答えてください。
すぐに答えてもらうと、100 の場合、200の場合、300の場合などについて
それに対応できるコードやデータ構造をアドバイスできたのに。

char mapdate[HEIGHT][WIDTH]; を
int mapdate[HEIGHT][WIDTH]; や
char mapdate[HEIGHT][WIDTH][2]; や
std::string mapdate[HEIGHT][WIDTH]; などにするやり方があります。

char mapdate[HEIGHT][WIDTH]; のままで stringstream を使うとすれば
次のようなコードになるでしょう。

コード:

#include <sstream>   // istringstream

/////////////////////////////ここまで////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		std::istringstream iss(buf);
		iss >> std::hex;
		for (int x = 0; x < WIDTH; x++) {
			int v; iss >> v;
			mapdata[y][x] = v;
			char c; iss >> c;   // skip ','
		}
	}
/////////////////////////////ここまで////////////////////////////

unsigned char, 0x11, 0xAA の修正も必要

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#25

投稿記事 by プログラマ見習い » 5年前

かずまさん。すみません。
まずは三つの質問に一つずつ質問に答えます。


●「media/map1 ですが、提示されたものは、空行 2行、データ 11行、空行 3行
になっていますよ。いいんですか?」

 自分では15行40列のものをアップロードしたつもりだったものが、間違いを指摘されて見直して修正した後、再びアップロードつもりだったのですけど、直っていませんでしたか?
 一応、新しいのをアップロードします。間違っている部分をもう少し詳しく教えてください。

map0.txt

コード:

 

0000000000111111111100000000001111111111
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000AAA000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000AAA000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000111111111100000000001111111111

 
map1.txt

コード:

 
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11

 

●「charの変数に入らない '11' や 'AA' などのデータを使わず、'0'、'1'、'A' にしました。」

 これについては、必要なデータの種類が62を超えた場合どうするんだと言う焦りがありました。それと、Aやaなど、文字列を使うのはcharを使うのが良いと書籍やネットにか書いてあったので、そのままcharを使い続けてしまいました。
 charでは1ケタでないと都合が悪い理由は、charが2進数で256個しか表現出来ない事が理由であると理解しても良いのでしょうか?



●「何種類のデータが必要ですか? 必ず答えてください。」

 具体的な数字をいくつ出せばいいのか迷っていました。控えめな数字の方が良いのか、欲を張っても良いのか。現状では100もあれば安心ですが、将来の事を考えて、欲を張って1000と答えます。
 必要な種類のデータ数によって、プログラムを組む考え方も、大きく、根本的に変わってくるのでしょうか?

 かずまさんが投稿して下さったソースコードについての回答は、後ほどします。

アバター
かめのこのこのこ
記事: 15
登録日時: 7年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#26

投稿記事 by かめのこのこのこ » 5年前

プログラマ見習い さんが書きました:
5年前
かめのこのこのこさん。
はい。その通りです。
mapdata[0][0]="00";
mapdata[0][1]="00";
mapdata[0][2]="00";
mapdata[0][?]="11"
~~~~~~省略
mapdata[?][?]="AA";
~~~~~~省略
この把握で宜しいです。
了解なのです
  • カンマ区切りの文字を読み込む事 or カンマを読み込まないで読み込みたい文字列だけを読み込む
  • 2ケタの文字を読み込む事 or 00,11,AAなど、一組の文字列として読み込む
の(私の考えている)実装を明日以降返信します
(ある程度頭の中で固まってきてはいますが、プログラマ見習いさんにどのように伝えればわかりやすいかというところ考えきれてないので、もうしばらく時間が欲しいです)

---------------------------------------------------------------------------------

そしてプログラマ見習いさんとかずまさんのやりとりに横槍を刺すとして..
プログラマ見習い さんが書きました:
5年前
●「charの変数に入らない '11' や 'AA' などのデータを使わず、'0'、'1'、'A' にしました。」

 これについては、必要なデータの種類が62を超えた場合どうするんだと言う焦りがありました。それと、Aやaなど、文字列を使うのはcharを使うのが良いと書籍やネットにか書いてあったので、そのままcharを使い続けてしまいました。
 charでは1ケタでないと都合が悪い理由は、charが2進数で256個しか表現出来ない事が理由であると理解しても良いのでしょうか?
プログラマ見習いさん、以下の3点に目を通して欲しいです
  • プログラミングにおいて、文字」と「文字列」は区別されます。「文字」は A や a などの文字1つを表し、「文字列」は「文字」を複数並べたものです。
  • C言語のソースコード上では、「文字」を 'A' や 'a' のように ' (シングルクォーテーション)で囲って表現し、「文字列」を "Hello, world!" のように " (ダブルクォーテーション) で囲って表現します。
    ( 'a' と "a" が別物であることのややこしさだったり..)
  • C言語の変数では、charが「文字」を保存できる型であり、「文字列」は往往にして charの配列 を使って保存します。(C++もOKならば stringも「文字列」を保存できます。)

    コード:

    char moji = 'A'; // 文字 A をcharの変数 moji に保存
    char mojiretsu[5] = "Hei!"; // 文字列 Hei! をcharの配列の変数 mojiretsu に保存
    
    ここで、配列の変数 mojiretsu の中身は
    mojiretsu[0]mojiretsu[1]mojiretsu[2]mojiretsu[3]mojiretsu[4]
    'H''e''i''!''\0'
以上の3点のこと、もしくは別のことで、もしわからないことがあれば、気軽に質問してくださいなのです。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#27

投稿記事 by プログラマ見習い » 5年前

 かめのこのこのさん。
 ありがとうございます。
 文字と文字列。文字が''で、文字列が""。気を取られていて初歩的な事を意識するのを忘れていました。



 かずまさん。
 かずまさんが投稿して下さったソースコードを読んで、コメント文に自分なりに理解した所をまとめました。

コード:

 

#include <DxLib.h>

#define MAPSIZE 32

#define HEIGHT 15
#define WIDTH  40

#define CHARA (HEIGHT * WIDTH)

struct ImageData {
	int kabe01;
	int teki0A[2];
};

struct ImageData im;

struct CharaData {
	char kind;
	int anime_pattern;
	int x, y;
	int body;
};
int counter;

struct CharaData charadata[CHARA];
unsigned int g_anime_counter = 0;
char mapdata[HEIGHT][WIDTH];

void MapLoad()
{
	ZeroMemory(charadata, sizeof(charadata));

	char buf[1024];
	//strcpy_s(buf, "media/map1.txt"); //☆strcpyのままではエラー警告C4996が出たので、strcpy_sに修正しました。また、sprintf_sに修正しても、描画自体は出来ました。
        sprintf_s(buf, "media/map1.txt"); //
	int fh = FileRead_open(buf);
	if (fh == NULL) { printfDx("ファイル読み込みエラー"); return; }

	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fh) == -1) break;
		char *p = buf;                          // ★
		for (int x = 0; x < WIDTH; x++) {       // ★
			mapdata[y][x] = strtol(p, &p, 16);  //★strol関数は、第一引数をlong型に変換する関数。
			p++; // skip ','                    // ★
		}                                       // ★
	}
	FileRead_close(fh);
}
 //strol関数(const char *nptr,char **endptr,int base);
 //strol関数は、第一引数(const char *nptr)をlong型に変換する関数。
 //第三引数(int base)は基数。16進数や2進数など、指定した進数に変換。

void Load()
{
	im.kabe01 = LoadGraph("media/kabe01.png"); //☆画像形式をpngに修正しました。
	LoadDivGraph("media/teki0A.png", 2, 2, 1, 32, 32, im.teki0A);
}

void Init()
{
	counter = 0;
	for (int y = 0; y < HEIGHT; y++) {
		for (int x = 0; x < WIDTH; x++) {
			unsigned char c = mapdata[y][x];  // ★こことInit関数内のunsigned charをunsigned intにすると、0x11の画像が表示されなくなりました。
                        unsigned int c = mapdata[y][x];  // ★
                        //char c= mapdata[y][x]; //☆こことMove関数内のunsignedを取ってしまうと、0x11が表示されなくなりました。
			charadata[counter].kind = c;
			charadata[counter].x = x * MAPSIZE;
			charadata[counter].y = y * MAPSIZE;
			switch (c) {
			case 0x11:  // ★16進数の整数に変換されたので、文字列''では駄目。
				charadata[counter].body = 1;
				mapdata[y][x] = '0';
				counter++;
				break;
			case 0xAA:  // ★
				charadata[counter].anime_pattern = 2;
				charadata[counter].body = 1;
				mapdata[y][x] = '0';
				counter++;
				break;
			}
		}
	}
}

void Move()
{
	for (int i = 0; i < counter; i++) {
		unsigned char c = charadata[i].kind;  // ★
                //unsigned int c = charadata[i].kind;  //
                //char c = charadata[i].kind;  ////☆
		switch (c) {
		case 0x11:  // ★
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
			break;

		case 0xAA:  // ★
			int a = g_anime_counter / 20 % charadata[i].anime_pattern;
			DrawGraph(charadata[i].x, charadata[i].y, im.teki0A[a], TRUE);
			break;
		}
		charadata[i].x = charadata[i].x - 1;
	}
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
	if (ChangeWindowMode(TRUE) != 0) return -1;
	if (DxLib_Init() != 0) return -1;
	if (SetDrawScreen(DX_SCREEN_BACK) != 0) return -1;

	MapLoad();
	Load();
	Init();

	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		if (ClearDrawScreen() != 0) return -1;
		Move();
		g_anime_counter++;
		if (ScreenFlip() != 0) return -1;
	}

	if (DxLib_End() != 0) return -1;
	return 0;
}

 
 気になる所があったので質問します。
 「16進数で書けば256種類のデータを扱える」点について、256種類が限界である理由をchar型の限界が256にあると理解していたので、では256種類を超えるにはunsigned char型をunsigned int型にすれば良いのではと思い、、unsigned int型にしてコンパイルした所、0x11の部分が表示されなくなりました。
 0x11の10進数の17で、0xAAは10進数の170なので、unsignedのないchar型だと0x11がマイナスの部分に入ってしまう事が原因だと理解していたので、unsigned int型0x11でも表示されない事にびっくりしました。

 改めて調べてみると、コンピュータが2進数を基礎としているので、256種類がコンピュータの限界だと理解してもいいのでしょうか?ゲームでも255の数字が良く使われているそうです。
 もしも256種類を超える種類のデータが必要な場合、上記のソースコードにどのような変更が必要なのでしょうか?
 ただ、コンピュータの性質上、よほどの事がない限り256種類を超えるデータはお勧めしないと指摘されたら、深入りしないで、256種類にとどめておきます。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#28

投稿記事 by プログラマ見習い » 5年前

みけCTAさん。

 みけCATさんが投稿してくれた、strchrとstrcmpのソースコードについての返答が遅れてすみませんでした。
 貴重なアドバイスをありがとうございます。

 コンパイルすると、残念ながら、画面は描画されませんでした。
 ソースコードを入れておきます。

コード:

#include <DxLib.h>
#include <cstring>

#define MAPSIZE 32 //マップサイズを決めます。

#define HEIGHT 15 //Y座標の最大値を決めます
#define WIDTH 40 //X座標の最大値を決めます

 //キャラクターの数の最大値を決めます。念のために多めにします。今回はマップデータの数に合わせます。
#define CHARA HEIGHT*WIDTH



 //画像データの構造体を作ります。
 //画像データは無理に配列やポインタで整理しようとすると、エラーやフリーズの原因になります。
struct ImageData{

 int kabe01; //
 int teki0A[2]; //

};

struct ImageData im; //



 //各キャラクターのデータの構造体を作ります。
struct CharaData{

 //int *ghandle; //アニメーションさせるために画像データハンドル。
 //ポインタ設定をしたが、これが原因の一つでした。

 char kind; //キャラクターの種類を格納。
 int anime_pattern; //アニメパーン数
 float x; //座標はfloatにします。
 float y;
 int body; //体力

};

struct CharaData charadata[CHARA]; //今回はcharadataと名づけます。
 //キャラクターは複数出現させるので、配列内に各キャラクターの最大値CHMAXを格納します。

//struct CharaData im[2]; //画像を描画するための変数。
//or//struct CharaData im[CHARA]; //画像を描画するための変数。



 //アニメーションカウンター用の変数を作ります。
unsigned int g_anime_counter=0;



 //マップデータを作ります。
char mapdata[HEIGHT][WIDTH];



  //メモ帳からマップデータを読み込み
void MapLoad(){

  //各キャラクターのデータを初期化します。
 ZeroMemory(charadata,sizeof(charadata));

 char buf[1024];
 sprintf_s(buf,1024,"media/map%d.txt",1); //ファイル名を用意する
 int fp; //ファイルハンドル
 fp=FileRead_open(buf); //ファイルを開く

  //ファイル読み込みエラー処理
 if(fp==NULL){
  printfDx("ファイル読み込みエラー");
  return;
 }



/////////////////////////////ここから////////////////////////////



 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){

  //★これは文字列の読み込み先として無効な可能性が高いポインタを指定することになるのでダメ
  //FileRead_scanf(fp,"%s",mapdata[y][x]);



   //★1セル分のデータを読み込む場所を作る
  char input[1024], *cr; //☆ポインタ指定を忘れずに。

   //★1セル分のデータを読み込む
  FileRead_scanf(fp,"%1023[^\n,]%*c",input);

   //★ゴミが付いている場合があるので、外す
  if ((cr = strchr(input, '\r')) != NULL) *cr = '\0';
 //☆strchr関数。文字列の中の文字を検索する関数。

   //★データを変換する
  if (strcmp(input, "00") == 0) mapdata[y][x] ='00'; //☆0を'00'に修正しました。0のままで修正しなくても、結果は同じでした。
  else if (strcmp(input, "11") == 0) mapdata[y][x] = '11';
  else if (strcmp(input, "AA") == 0) mapdata[y][x] = 'AA';
  else x--; // 変換できなかった場合、なかったことにする
    //else{x--;continue;}にしてもダメ。
   //☆strcmp関数。文字列を比較する関数。



  } //for(int x=0;x<WIDTH;x++)の最後
 } //for(int y=0;y<HEIGHT;y++)の最後

/////////////////////////////ここまで////////////////////////////

 FileRead_close(fp); //ファイルを閉じる

} //void MapLoad();の最後



 //画像をロードする関数を作ります。
void Load(){

 im.kabe01=LoadGraph("media/kabe01.png");//画像形式をpngにする。

 LoadDivGraph("media/teki0A.png",2,2,1,32,32,im.teki0A);

}



 //初期化用の関数を作ります。
void Init(){

  //キャラクターをカウントする変数を作ります。必要な変数の一つです。
  //キャラクターをカウントする変数はローカル変数でも問題ありませんでした。
 int counter=0;

 for(int y=0;y<HEIGHT;y++){
  for(int x=0;x<WIDTH;x++){

  char c=mapdata[y][x];

   //初期化してマップデータから、キャラクターのデータを取り出します。

   //kindにマップデータを代入します。
   //これも必要な変数の一つです。
  charadata[counter].kind=c;

  charadata[counter].x=(float)x*MAPSIZE;
  charadata[counter].y=(float)y*MAPSIZE;

  int charaValid=0;
   //この変数を利用しないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   //Validは英語で「有効、根拠の確実な、確かな、正当な」などの意味です。

   //キャラクターごとに異なるものはswicth文を使います。
  switch(c){ //なお、ここにcounterを入れてしまうと、フリーズしてしまいました。
   case '11':
    charadata[counter].body=1;
    charaValid=1; //case毎にcv=1;と代入します。
    break;

   case 'AA':
    charadata[counter].anime_pattern=2; //アニメーションさせる場合はここで代入します。
    charadata[counter].body=1;
    charaValid=1; //
    break;

  }

    //このif文がないと初期化関数Init();をwhile文に入れた場合に適切に描画されません。
   if(charaValid){
   mapdata[y][x]='0'; //マップデータを'0'にする事で、データの取り出しは終わりです。
    //ここでキャラクターの数を一つずつ増やしていきます。
   counter++;
   }

  }
 }

}


 //描画と移動処理用の関数を作ります
void Move(){

 for(int i=0;i<CHARA;i++){

  char c=charadata[i].kind;

  switch(c){
   //ここにcharadata[i].kindではなくiを入れると、一つしか描画されませんでした。
   //また、フリーズしてまった場合もあります。

   case '11':
    DrawGraph(charadata[i].x,charadata[i].y,im.kabe01,TRUE);
  
    break;

   case 'AA':
    int a=g_anime_counter/20%charadata[i].anime_pattern;
    DrawGraph(charadata[i].x,charadata[i].y,im.teki0A[a],TRUE);

    break;

  }

   //キャラクター単位で動かす方法でマップスクロールを行います。
  charadata[i].x=charadata[i].x-1;

 }

}



 //WinMain関数の中に、先ほど作った関数を入れます。//Move();だけwhile内に入れます。
int WINAPI WinMain(HINSTANCE hI,HINSTANCE hP,LPSTR lpC,int nC){

 if(ChangeWindowMode(TRUE)!=0) return -1; //ウィンドウモードの変更
 if(DxLib_Init()!=0) return -1; //DXライブラリ初期化処理
 if(SetDrawScreen(DX_SCREEN_BACK)!=0) return -1; //描画先を裏画面に設定


 //ロードの関数は、ここではここに入れます。


 MapLoad(); //マップデータのロード

 Load(); //画像のロード 

 Init(); //初期化。//if(charaValid)に関するコードを書いていない時は、ここに置かないで、while文の中に置くと、適切に描画されません。



 while(ProcessMessage()==0&&CheckHitKey(KEY_INPUT_ESCAPE)==0){
  //メッセージ処理(XキーかAlt+F4キーが押されたら終了)
  //ESCキーが押されたら終了
 if(ClearDrawScreen()!=0) return -1; //裏画面を消す


  //Init(); //初期化。//if(charaValid)に関するコードを書いていないでwhile文の中に初期化関数Init();置くと、適切に描画されません。
   //この関数をそのままwhile文の中に入れてしまうと、一番最初の画像が消えてしまう。

  Move(); //画像の描画と移動用の関数をここに置きます。

  g_anime_counter++; //



  if(ScreenFlip()!=0) return -1; //裏画面を表画面に反映

 }

 if(DxLib_End()!=0) return -1; //DXライブラリの終了処理
 return 0; //ソフトの終了

}



「複数文字の文字定数がどのような値になるかは、処理系定義です。
GCC 4.8.1では動きませんでしたが、MathさんのいうVS2019なら動くかもしれません。」と言う事でしたので、vs2017communityには対応していないのかもしれません。それともまた私の記述ミス?上記のソースコードはコピペです。

アバター
usao
記事: 1889
登録日時: 11年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#29

投稿記事 by usao » 5年前

オフトピック
> 第一に、以上のような1ケタずつ読み込んでいく方法だと、整数10個、アルファベット大文字26文字、小文字26文字で、合計62種類までのデータを読み込む事が出来ます。

この話だと,1データを「数字とアルファベットからなる2文字」にすることで62*62=3844パターンを表現するという世界を目指していることになる.
ファイルに書かれている"11"だの"AA"だのいうのは16進文字列ではないのだろうから,
strtol(p, &p, 16)
だと目指す仕様と違うんじゃないの?

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

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#30

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

プログラマ見習い さんが書きました:
5年前
 気になる所があったので質問します。
 「16進数で書けば256種類のデータを扱える」点について、256種類が限界である理由をchar型の限界が256にあると理解していたので、では256種類を超えるにはunsigned char型をunsigned int型にすれば良いのではと思い、、unsigned int型にしてコンパイルした所、0x11の部分が表示されなくなりました。
 0x11の10進数の17で、0xAAは10進数の170なので、unsignedのないchar型だと0x11がマイナスの部分に入ってしまう事が原因だと理解していたので、unsigned int型0x11でも表示されない事にびっくりしました。
手元で試したところ、unsigned int型の場合、
逆に0x11のキャラクターは表示されるが、0xAAのキャラクターは表示されない現象を観測できました。
これは、char型が符号(2の補数)付き8ビット、unsigned int型が32ビットであると仮定すると、
char型の変数に入れられた0xAAは負の数-86となり、
これをunsigned int型に変換すると0xFFFFFFAAとなるため、
caseの0xAAとは一致しなくなるからであると考えられます。
(0xFFFFFFAAとなるのは負の数を変換先の符号なし整数の最大値+1を足して範囲内に変換するため、
もしくは符号拡張(もとの数を最上位ビットをコピーして拡張)するため)

プログラマ見習いさんの環境では、本当に0x11の部分が表示されなくなったのですか?
プログラマ見習い さんが書きました:
5年前
改めて調べてみると、コンピュータが2進数を基礎としているので、256種類がコンピュータの限界だと理解してもいいのでしょうか?ゲームでも255の数字が良く使われているそうです。
いいえ。
もし2進数を基礎としているからというなら、2種類がコンピュータの限界となるでしょう。
現代のコンピュータでは8個のビット(0か1かの情報)をまとめて単位(バイト、またはオクテット)として扱い、
この1バイトで表せるのが256種類です。
そして、複数のバイトを組み合わせることで、
単純計算で256の(組み合わせるバイト数)乗種類のデータを表すことができます。
2バイトなら65,536種類、4バイトなら4,294,967,296(約43億)種類、
8バイトなら18,446,744,073,709,551,616(約2千京)種類となります。
(現実では、コマンドとして解釈される、誤りの検出や訂正を行う、
などの理由で禁止されるバイトの組み合わせがあり、データの種類数が少なくなる場合もあります)
プログラマ見習い さんが書きました:
5年前
もしも256種類を超える種類のデータが必要な場合、上記のソースコードにどのような変更が必要なのでしょうか?
やりたいことを実現するようにする変更が必要でしょう。
これまでの回答者の方々のアドバイスが参考になることを期待します。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#31

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

プログラマ見習い さんが書きました:
5年前
では256種類を超えるにはunsigned char型をunsigned int型にすれば良いのではと思い
いくらmapdataの要素を格納する一時変数をunsigned int型にしても、
肝心のmapdataの要素(やキャラクターのkind)がcharのままでは、
charの範囲を超えるデータを読み込むことはできません。
したがって、拡張するならここも拡張するべきです。
プログラマ見習い さんが書きました:
5年前
一応、新しいのをアップロードします。間違っている部分をもう少し詳しく教えてください。

map0.txt

コード:

 

0000000000111111111100000000001111111111
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000AAA000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000AAA000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0000000000111111111100000000001111111111

 
map1.txt

コード:

 
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,AA,AA,AA,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11,00,00,00,00,00,00,00,00,00,00,11,11,11,11,11,11,11,11,11,11

 
まだ空行やスペースだけの行が入っていますね。
もちろん、このようなデータに対応したいのであれば、
空行やスペースだけの行を無視するコードを入れればいいでしょう。
もしくは、「十六進数として有効なデータ以外を無視する」でもいいでしょう。
(私の#21のコードは、「あらかじめ決めた数種類のデータ以外を無視する」ことで、対応させています)
プログラマ見習い さんが書きました:
5年前
 みけCATさんが投稿してくれた、strchrとstrcmpのソースコードについての返答が遅れてすみませんでした。
 貴重なアドバイスをありがとうございます。

 コンパイルすると、残念ながら、画面は描画されませんでした。
 ソースコードを入れておきます。
この#28のコードについて、「'11'」を「(char)0x11」に、「'AA'」を「(char)0xAA」に、
それぞれ3箇所書き換えて実行したところ、手元の環境で画像が表示されることを確認しました。
したがって、問題は処理系定義の複数文字の文字定数を使っていることであると考えられます。
プログラマ見習いさんの環境ではどうなりますか?
一応、データファイルも添付します。
添付ファイル
media.zip
#28用データファイル
(1.72 KiB) ダウンロード数: 400 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#32

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

オフトピック
プログラマ見習い さんが書きました:
5年前
かめのこのこのさん。
プログラマ見習い さんが書きました:
5年前
みけCTAさん。
名前の間違いがみられますね。
ここもコピペするといいかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#33

投稿記事 by かずま » 5年前

JIS X3010:2003 (ISO/IEC 9899:1999) さんが書きました: 6.4.4.4文字定数
 ...
意味規則 単純文字定数は,型 int をもつ。1 バイトの実行文字に対応する
単一の文字を含む単純文字定数の値は,対応付けた文字の表現を整数として
解釈した数値とする。2 文字以上を含む(例えば'ab')又は 1 バイトの実行
文字で表現できない文字若しくは逆斜線表記を含む単純文字定数の値は,
処理系定義とする。
'ab' が処理系定義なので、調べてみます。

コード:

#include <stdio.h>

int main(void)
{
	printf("%x\n", 'a');
	printf("%x\n", 'b');
	printf("%x\n", 'ab');
}
VC++ と gcc の実行結果は同じ。

コード:

61
62
6162
先頭文字が上位バイト、後続文字が下位バイトだと分かったので
mapdata と .kind を short(16ビット) にします。
これで 2文字格納できます。1000種類でも大丈夫です。
画像ファイルは PNG としました。

コード:

#include <DxLib.h>

#define MAPSIZE 32

#define HEIGHT 15
#define WIDTH 40

#define CHARA (HEIGHT * WIDTH)

struct ImageData {
	int kabe01;
	int teki0A[2];
};

struct ImageData im;

struct CharaData {
	short kind; // ★ short: 256種類以上格納するため
	int anime_pattern;
	int x;    // ★ DrawGraph に使用するので float ではなく int
	int y;
	int body; //体力
};

struct CharaData charadata[CHARA];
int counter; // ★ CHARA個のうち実際には counter個を使用

unsigned int g_anime_counter = 0;

short mapdata[HEIGHT][WIDTH]; // ★ short: 256種類以上格納するため

void MapLoad()
{
	char buf[1024];
	sprintf_s(buf, 1024, "media/map%d.txt", 1);
	int fp = FileRead_open(buf);  // ★ fp はファイルハンドル
	if (fp == 0) { printfDx("ファイル読み込みエラー"); return; }
/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		char *p = buf;
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = p[0]<<8 | p[1]; // ★ 先頭文字が short の上位バイト
			p += 3;
		}
	}
/////////////////////////////ここまで////////////////////////////
	FileRead_close(fp);
}

void Load()
{
	im.kabe01 = LoadGraph("media/kabe01.png");
	LoadDivGraph("media/teki0A.png", 2, 2, 1, 32, 32, im.teki0A);
}

void Init()
{
	ZeroMemory(charadata, sizeof(charadata));  // ★ ここで初期化が適切
	counter = 0;
	for (int y = 0; y < HEIGHT; y++) {
		for (int x = 0; x < WIDTH; x++) {
			short c = mapdata[y][x];	// ★ short
			charadata[counter].kind = c;
			charadata[counter].x = x * MAPSIZE;
			charadata[counter].y = y * MAPSIZE;
			switch (c) {
			case '11':
				charadata[counter].body = 1;
				break;
			case 'AA':
				charadata[counter].anime_pattern = 2;
				charadata[counter].body = 1;
				break;
			}
			if (charadata[counter].body) {  // ★ charaValid の代わり
				// mapdata[y][x] = '0';  // ★ 不要では? '0' と '00' は異なる値
				counter++;
			}
		}
	}
}

void Move()
{
	for (int i = 0; i < counter; i++) {  // ★ counter個を描画
		short c = charadata[i].kind; // ★ short
		switch (c) {
		case '11':
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
			break;
		case 'AA':
			int a = g_anime_counter / 20 % charadata[i].anime_pattern;
			DrawGraph(charadata[i].x, charadata[i].y, im.teki0A[a], TRUE);
			break;
		}
		charadata[i].x = charadata[i].x - 1;
	}
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
	if (ChangeWindowMode(TRUE) != 0) return -1;
	if (DxLib_Init() != 0) return -1;
	if (SetDrawScreen(DX_SCREEN_BACK) != 0) return -1;

	MapLoad();
	Load();
	Init();

	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		if (ClearDrawScreen() != 0) return -1;
		Move();
		g_anime_counter++;
		if (ScreenFlip() != 0) return -1;
	}

	if (DxLib_End() != 0) return -1;
	return 0;
}

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#34

投稿記事 by かずま » 5年前

コード:

#include <stdio.h>

int main(void)
{
	printf("%x\n", 'ア');
	printf("%x\n", 'イ');
	printf("%x\n", 'アイ');
}
Visual C++ での実行結果

コード:

ffffffb1
ffffffb2
b1b2
char *p = buf; で
mapdata[y][x] = p[0]<<8 | p[1]; だと
'アア' が 0xffffffb1 になるので、次のように変更します。

コード:

		unsigned char *p = (unsigned char *)buf; // ★
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = p[0]<<8 | p[1]; // ★ 先頭文字が上位
			p += 3;
		}
map1.txt の中の XX,XX,XX,.. の XX は 16進数でなくなったので
文字なら何でも構いません。
'0'~'9'、'A'~'Z'、'a'~'z' の 62文字に限らず
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ の 32文字も使えます。
スペースも使えます。
。「」、・ヲァィゥェォャュョッーアイウエオ...ラリルレロワン゙゚ の 63文字も使えます。
全部で 158文字なので、158x158 = 24964種類の mapdata を扱えます。

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#35

投稿記事 by かずま » 5年前

かずま さんが書きました:
5年前
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ の 32文字も使えます。
スペースも使えます。
。「」、・ヲァィゥェォャュョッーアイウエオ...ラリルレロワン゙゚ の 63文字も使えます。
全部で 158文字なので、158x158 = 24964種類の mapdata を扱えます。
mapdata や .kind を short から unsigned short に変更が必要です。
unsigned short c = もです。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#36

投稿記事 by プログラマ見習い » 5年前

皆さん。貴重なアドバイスありがとうございます。
事情があって返信が遅れています。
今回はメモ帳の問題に絞って返信します。

空行やスペースの問題についてですが、投稿の際に、私がコード貼り付けタグを使ったのが原因ではないかと思います。
今度はmap0.txtとmap1.txtを添付ファイルとして送ります。
問題点がないかどうかのお確かめをお願いします。

みけCATさん。
かめのこのこのこ さん。
名前を間違ってすみません。
名前もコピペします。
添付ファイル
map1.txt
(1.77 KiB) ダウンロード数: 380 回
map0.txt
(632 バイト) ダウンロード数: 396 回

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#37

投稿記事 by プログラマ見習い » 5年前

 かずまさん。
 かすまさんが投稿してくれたソースコードをコンパイルしたら、画像が描画されました。
 その後、いろいろと調べていくと、まず自分のint型やchar型などの変数に対する認識がいかに甘かったが分かりました。
 変数とビット数やバイト数との関係が、このような場合に生きてくるのかと言う驚きです。。
 文字が内部では8ケタの整数で処理される事の意味を今まで理解していませんでした。

 char型が8ビットで、short型が16ビット、int型は32と64の2種類を確認しました。

 以下のソースコードについても、自分で調べてみました。
/////////////////////////////ここから////////////////////////////
for (int y = 0; y < HEIGHT; y++) {
if (FileRead_gets(buf, 1024, fp) == -1) break;
char *p = buf;
for (int x = 0; x < WIDTH; x++) {
mapdata[y][x] = p[0]<<8 | p[1]; // ★ 先頭文字が short の上位バイト //☆<<はシフト演算子。
//☆シフト演算子は、<<で右シフト。>>で左シフト。
//☆<<8で、8ビットシフト。
//「|」はビットごとのOR。
p += 3; //☆は、「00,」「11,」「AA,」で、三文字分あるので、「3」だけ増やす。
}
}
/////////////////////////////ここまで////////////////////////////

 どの程度理解で出来たかと言うと、誤解を恐れずに言うと、内部で処理されている様子を頭で想像出来る程度と言う事です。具体的な事については確信を持てません。
 特に今でも理解出来ていないのが、「mapdata[y][x] = p[0]<<8 | p[1];」の部分のp[0]とp[1]の意義についてです。
 今、皆さんのアドバイスを元に、00,11,AA,など、カンマで区切られた整数ないし文字をマップデータとして読み込みための自分が使いこなせる解決策を考える所です。

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#38

投稿記事 by かずま » 5年前

ポインタが分からないのなら、次のようにも書けます。

コード:

/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		int i = 0;
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = buf[i]<<8 | buf[i+1];
			i += 3;
		}
	}
/////////////////////////////ここまで////////////////////////////
ビット演算が苦手なら、次のようにも書けます。

コード:

/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		int i = 0;
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = buf[i]*256 + buf[i+1];
			i += 3;
		}
	}
/////////////////////////////ここまで////////////////////////////

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#39

投稿記事 by プログラマ見習い » 5年前

かずまさん。

貴重なアドバイス、ありがとうございます。
上記の二つのソースコードに対する返信は、研究に時間がかかるので、後ほどします。

 皆さんのアドバイスを参考にして、自分が使いこなせそうな解決策を一つ選びました。
 内容を大まかに述べると、strtol関数を利用する事と、10進数をベースにする事です。
 実質、00,01,11のような二桁のカンマで区切られた整数を利用する事にとどめて、AA,BBなどのアルファベットを利用しない方法です。

 ソースコードを載せます。添付ファイルmap2.txtを載せます。中身は00,01,11の三種類です。

コード:

#include <DxLib.h>

#define MAPSIZE 32

#define HEIGHT 15
#define WIDTH  40

#define CHARA (HEIGHT * WIDTH)

struct ImageData {
	int kabe01;
	int teki0A[2];
};

struct ImageData im;

struct CharaData {
	//char kind; //☆
        int kind; //☆
        //short kind //☆
	int anime_pattern;
	int x, y;
	int body;
};
int counter;

struct CharaData charadata[CHARA];
unsigned int g_anime_counter = 0;

//char mapdata[HEIGHT][WIDTH];
int mapdata[HEIGHT][WIDTH];

void MapLoad()
{
	ZeroMemory(charadata, sizeof(charadata));

	char buf[1024];
	  //strcpy(buf, "media/map%d.txt",2); //☆マップファイルをmap2.txtに変更。
        sprintf_s(buf, "media/map%d.txt",2); //☆s_printf_s関数に変更。
         //sprintf_s(buf, "media/map%d.txt",3); //☆map3.txtはAの文字が入っているので、読み込もうとすると「ファイル読み込みエラー」になる。
	int fh = FileRead_open(buf);
	if (fh == NULL) { printfDx("ファイル読み込みエラー"); return; }


//////////ここから//////////

	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fh) == -1) break;
		char *p = buf;                          // ★
		for (int x = 0; x < WIDTH; x++) {       // ★
			   //mapdata[y][x] = strtol(p, &p, 16);  // ★
                        mapdata[y][x] = strtol(p, &p, 10); //☆10進数に変更
			p++; // skip ','                    // ★ ☆スキップ
		}                                       // ★
	}

//////////ここまで//////////

	FileRead_close(fh);
}

void Load()
{
	im.kabe01 = LoadGraph("media/kabe01.png"); //☆今回は画像形式をpngにする。
	LoadDivGraph("media/teki0A.png", 2, 2, 1, 32, 32, im.teki0A);
}

void Init()
{
	counter = 0;
	for (int y = 0; y < HEIGHT; y++) {
		for (int x = 0; x < WIDTH; x++) {
			 //unsigned char c = mapdata[y][x];  // ★
                        //int c=mapdata[y][x]; //☆unsignedなしでも描画された。
                        unsigned int c=mapdata[y][x]; //☆
                         //short c=mapdata[y][x]; //☆
			charadata[counter].kind = c;
			charadata[counter].x = x * MAPSIZE;
			charadata[counter].y = y * MAPSIZE;
			switch (c) {
			  //case 0x11:  // ★
                         case 01: //☆10進数に変更のため変更。
				charadata[counter].body = 1;
				mapdata[y][x] = '0';
				counter++;
				break;
			   //case 0xAA:  // ★
                          case 11: //☆10進数変更のため変更
				charadata[counter].anime_pattern = 2;
				charadata[counter].body = 1;
				 //mapdata[y][x] = '00'; //☆間違えて'0'のままにしていた。
                                mapdata[y][x]=00; //☆00に変更
				counter++;
				break;
			}
		}
	}
}

void Move()
{
	for (int i = 0; i < counter; i++) {
		 //unsigned char c = charadata[i].kind;  // ★
                //int c=charadata[i].kind;  //☆unsignedなしでも描画された。
                unsigned int c=charadata[i].kind;  //☆
                //short int c=charadata[i].kind;  //☆
		switch (c) {
		 //case 0x11:  // ★
                 case 01: //☆10進数に変更のため変更。
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
			break;

		 //case 0xAA:  // ★
                 case 11: //☆10進数に変更のため変更。
			int a = g_anime_counter / 20 % charadata[i].anime_pattern;
			DrawGraph(charadata[i].x, charadata[i].y, im.teki0A[a], TRUE);
			break;
		}
		charadata[i].x = charadata[i].x - 1;
	}
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
	if (ChangeWindowMode(TRUE) != 0) return -1;
	if (DxLib_Init() != 0) return -1;
	if (SetDrawScreen(DX_SCREEN_BACK) != 0) return -1;

	MapLoad();
	Load();
	Init();

	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		if (ClearDrawScreen() != 0) return -1;
		Move();
		g_anime_counter++;
		if (ScreenFlip() != 0) return -1;
	}

	if (DxLib_End() != 0) return -1;
	return 0;
}


 解決策の一つに、以上の方法を選んだのは、strtol関数に魅力を感じた事と、整数以外の文字を利用する事に限界を感じたからです。
 外部から読み込んだデータを整数に変換する方法(整数ベース)と比べて、文字や文字列のまま扱う方法(文字列ベース)は、複雑に感じて苦手意識から抜け出せません。

 私はファイル読み込みに対する苦手意識と、いろいろ試していけば何とかなるだろうと言う矛盾した意識をもって挑戦してきたのですが、自力では出来なかったのは周知のとおりです。
 
 それでもstrtol関数を利用した整数ベースについて自分なりとは言え理解出来る所まで辿り着けましたが、文字列ベースについては、まだです。

 文字列ベースでの解決策は、もう少し研究してみる事にします。

 ただ、strtol関数を利用した場合について、理解したとはいっても自分なりのイメージ過ぎないで、問題点があると思います。自分なりに理解、と言うよりも、イメージした部分を以下に示します。問題点があれば、アドバイスをお願いします。

コード:

//////////ここから//////////

	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fh) == -1) break;
		char *p = buf;                          // ★
		for (int x = 0; x < WIDTH; x++) {       // ★
			   //mapdata[y][x] = strtol(p, &p, 16);  // ★
                        mapdata[y][x] = strtol(p, &p, 10); //☆10進数に変更
			p++; // skip ','                    // ★ ☆スキップ
		}                                       // ★
	}

//////////ここまで//////////


strtol関数=文字列をlong型の整数に変換する関数。
#include <stdlib.h>
long strtol(const char *s, char **endptr, int base);
const char *s 第1引数 変換する対象の文字列を指定
char **endptr 第2引数 変換不可能な文字列を指定?
int base 基数 10進数や16進数などに変換

 ポインタは配列ではありませんが、あえて格納数の決まっていない配列と考える。そう考えないとイメージ出来ないからです。許して下さい。

char *p=buf;は、1024あるデータをいくつかのp[]に分割するための設定をするが、いくつかまではこの時点では指定されていない。
 for (int x = 0; x < WIDTH; x++)によって、WIDTH個まで分割される。

 bufは、base進数ずつ分割される。ここでは10進数ごとに分割される。
 なお、WIDTH個まで分割される前に、bufが不足すると、容量オーバーが起こるので、あらかじめ多めに設定しておく。bufが余るくらいが丁度よい。

 mapdata[y][x]=strtol(p, &p, 10);では、pと10を置く事で、いくつかあるp[]を一つずつ10進数に変換して、&pを置く事で、p[]が文字列から整数に変換される時に、外見まで変換されないようにする。
 例えば、p[]の中身が11の場合、メモ帳に書かれた11は、読み込まれた時点では文字列であるが、strtol関数によって10進数の整数に変換される場合、11がコンピューター内では11でない数値に変換される事がある。そこで、&pを置く事によって、文字列の11が整数に変換された場合でも、11と言う値が11以外の数値に変換されないようにする。
 p++によって、メモ帳のカンマ「,」を扱わないようにする。例えば、11の場合、p[]の中身は厳密には当初「11,」であるが、strtol(p, &p, 10);によって11の部分が整数に変換された後固定される。その後、p++によって固定されなかった「,」は無視されて、「11,」は「11」となり、「,」FileRead_close(fh);の際に破棄される。
添付ファイル
map2.txt
(1.77 KiB) ダウンロード数: 368 回

アバター
usao
記事: 1889
登録日時: 11年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#40

投稿記事 by usao » 5年前

オフトピック
そんな意味わからん長文書く前に,まずはstrtolをググればよくね?
(引数の意味について書こうとして「?」が付いている時点でダメだろ常考…)

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#41

投稿記事 by かずま » 5年前

プログラマ見習い さんが書きました:
5年前
strtol関数=文字列をlong型の整数に変換する関数。
#include <stdlib.h>
long strtol(const char *s, char **endptr, int base);
const char *s 第1引数 変換する対象の文字列を指定
char **endptr 第2引数 変換不可能な文字列を指定?
int base 基数 10進数や16進数などに変換
10進数や 16進数などに変換するのではなく、
10進数や 16進数などの文字列を long型の整数に変換します。

次のコードの実行結果をよく考えてください。

コード:

#include <stdio.h>
#include <stdlib.h>  // strtol

int main(void)
{
	int x, d, o;
	char s1[] = "127", s2[] = "15,72", s3[] = "  8cm";
	char *p1, *p2, *p3;

	x = strtol(s1, &p1, 16);
	d = strtol(s1, &p2, 10);
	o = strtol(s1, &p3, 8);
	printf("\ns1=%p, s1=\"%s\"\n", s1, s1);
	printf("p1=%p, *p1=%02x, x=%d\n", p1, *p1, x);
	printf("p2=%p, *p2=%02x, d=%d\n", p2, *p2, d);
	printf("p3=%p, *p3=%02x, o=%d\n", p3, *p3, o);

	x = strtol(s2, &p1, 16);
	d = strtol(s2, &p2, 10);
	o = strtol(s2, &p3, 8);
	printf("\ns2=%p, s2=\"%s\"\n", s2, s2);
	printf("p1=%p, *p1='%c', x=%d\n", p1, *p1, x);
	printf("p2=%p, *p2='%c', d=%d\n", p2, *p2, d);
	printf("p3=%p, *p3='%c', o=%d\n", p3, *p3, o);

	x = strtol(s3, &p1, 16);
	d = strtol(s3, &p2, 10);
	o = strtol(s3, &p3, 8);
	printf("\ns3=%p, s3=\"%s\"\n", s3, s3);
	printf("p1=%p, *p1='%c', x=%d\n", p1, *p1, x);
	printf("p2=%p, *p2='%c', d=%d\n", p2, *p2, d);
	printf("p3=%p, *p3='%c', o=%d\n", p3, *p3, o);
}
実行結果

コード:


s1=0135FB08, s1="127"
p1=0135FB0B, *p1=00, x=295
p2=0135FB0B, *p2=00, d=127
p3=0135FB0B, *p3=00, o=87

s2=0135FB20, s2="15,72"
p1=0135FB22, *p1=',', x=21
p2=0135FB22, *p2=',', d=15
p3=0135FB22, *p3=',', o=13

s3=0135FB18, s3="  8cm"
p1=0135FB1C, *p1='m', x=140
p2=0135FB1B, *p2='c', d=8
p3=0135FB18, *p3=' ', o=0
プログラマ見習い さんが書きました:
5年前
 ポインタは配列ではありませんが、あえて格納数の決まっていない配列と考える。そう考えないとイメージ出来ないからです。許して下さい。

char *p=buf;は、1024あるデータをいくつかのp[]に分割するための設定をするが、いくつかまではこの時点では指定されていない。
ポインタは配列ではありません。

char c = 'A'; char *p; p = &c; で、
ポインタ p の値は c のアドレスとなり、p は c を指します。
*p は c です。

次は、ポインタが配列の先頭要素に設定された場合について説明します。

char buf = "ABC"; char *p; p = buf; で、
ポインタ p の値は buf[0] のアドレスとなり、p は buf[0] を指します。
*p は buf[0] です。*p の値は 'A' です。
*p は p[0] と書いてもよいのです。

p+1 は、buf[1] のアドレスです。p+1 は buf[1] を指します。
*(p+1) は buf[1] です。*(p+1) の値は 'B' です。
*(p+1) は p[1] と書いてもよいのです。

p は、配列 buf を分割なんかしません。
配列の要素を指すだけです。
*(p+i) または p[ i] の値は、buf[ i] です。
プログラマ見習い さんが書きました:
5年前
 for (int x = 0; x < WIDTH; x++)によって、WIDTH個まで分割される。
mapdata[y] を mapdata[y][x] で参照することにより
個々の要素を参照することを分割といっているのでしょうか?
プログラマ見習い さんが書きました:
5年前
 bufは、base進数ずつ分割される。ここでは10進数ごとに分割される。
 なお、WIDTH個まで分割される前に、bufが不足すると、容量オーバーが起こるので、あらかじめ多めに設定しておく。bufが余るくらいが丁度よい。
buf を分割しているのではありません。
buf の先頭から順に見に行っているだけです。
buf には、WIDTH個の整数文字列があることを想定しています。
もし、 WIDTH個より少なくて、見ているところが buf 内の文字列の最後の '\0'
に達すると strtol は変換に失敗し、0 を返します。
ただそれだけのことです。容量オーバーの意味が分かりません。
プログラマ見習い さんが書きました:
5年前
 mapdata[y][x]=strtol(p, &p, 10);では、pと10を置く事で、いくつかあるp[]を一つずつ10進数に変換して、&pを置く事で、p[]が文字列から整数に変換される時に、外見まで変換されないようにする。
いくつかある p[] って何ですか?
p は buf の中のある位置を指していて、そこの文字から順番に読み取って
数値に変換していき、変換できなくなった文字の位置を p に返します。
引数で値を返すために &p で p のアドレスを渡しています。
「外見まで変換されない」の意味が分かりません。
プログラマ見習い さんが書きました:
5年前
 例えば、p[]の中身が11の場合、メモ帳に書かれた11は、読み込まれた時点では文字列であるが、strtol関数によって10進数の整数に変換される場合、11がコンピューター内では11でない数値に変換される事がある。そこで、&pを置く事によって、文字列の11が整数に変換された場合でも、11と言う値が11以外の数値に変換されないようにする。
 p++によって、メモ帳のカンマ「,」を扱わないようにする。例えば、11の場合、p[]の中身は厳密には当初「11,」であるが、strtol(p, &p, 10);によって11の部分が整数に変換された後固定される。その後、p++によって固定されなかった「,」は無視されて、「11,」は「11」となり、「,」FileRead_close(fh);の際に破棄される。
わけがわかりません。

buf[] = "00,11,34"; だったとします。
buf[0] は '0'、buf[2] は ','、buf[7] は '4'、buf[8] は '\0' です。
char *p = buf; で
p[0] は '0'、p[2] は ','、p[7] は '4'、p[8] は '\0' となります。

val = strtol(p, &p, 10); で
strtol は、p の指すところから順番に文字を見ていきます。
p[0] が '0'、p[1] が '0'、p[2] が ','。
ここで数字でない文字にぶち当たったので、それ以前を整数値 0 に変換し、
返却値として返すので、val は 0 になります。

そして、第2引数の p には、p[2] のアドレスすなわち p + 2 が返されます。
p は 2つ進みました。
それは、buf[2] のアドレスです。
p は buf[2] の ',' を指すようになりました。

p++; で p を一つ進めると、p は buf[3] の '1' を指すようになります。

val = strtol(p, &p, 10); で
strtol は、p の指すところから順番に文字を見ていきます。
p[0] が '1'、p[1] が '1'、p[2] が ','。
ここで数字でない文字にぶち当たったので、それ以前を整数値 11 に変換し、
返却値として返すので、val は 11 になります。

そして、第2引数の p には、p[2] のアドレスすなわち p + 2 が返されます。
p はさらに 2つ進みました。
それは、buf[5] のアドレスです。
p は buf[5] の ',' を指すようになりました。

p++; で p を一つ進めると、p は buf[6] の '3' を指すようになります。
val = strtol(p, &p, 10); で
strtol は、p の指すところから順番に文字を見ていきます。
p[0] が '3'、p[1] が '4'、p[2] が '\0'。
ここで数字でない文字にぶち当たったので、それ以前を整数値 34 に変換し、
返却値として返すので、val は 34 になります。

そして、第2引数の p には、p[2] のアドレスすなわち p + 2 が返されます。
p はさらに 2つ進みました。
それは、buf[8] のアドレスです。
p は buf[8] の '\0' を指すようになりました。

p は buf を分割しているのではなく、buf の中の文字を順番に見ていくことに
使用されています。

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#42

投稿記事 by かずま » 5年前

かずま さんが書きました:
5年前
char buf = "ABC"; char *p; p = buf; で、
すみません。次のように訂正します。
char buf[4] = "ABC"; char *p; p = buf; で、

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#43

投稿記事 by プログラマ見習い » 5年前

ググって調べて頭の中で整理したものを文章に書いただけです。本当にすみません。
ただ、本当に理解出来なかったので、間違って理解してる部分を正すために、あえて投稿しただけです。
不評だったので、このような文章を投稿するのはやめて、今後は素直にこの部分が理解出来なかったとだけ投稿する事にします。
ただ、自分も他人任せではなく、ちゃんと考えていることを示したかっただけです。

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#44

投稿記事 by かずま » 5年前

プログラマ見習い さんが書きました:
5年前
ググって調べて頭の中で整理したものを文章に書いただけです。本当にすみません。
ただ、本当に理解出来なかったので、間違って理解してる部分を正すために、あえて投稿しただけです。
不評だったので、このような文章を投稿するのはやめて、今後は素直にこの部分が理解出来なかったとだけ投稿する事にします。
ただ、自分も他人任せではなく、ちゃんと考えていることを示したかっただけです。
謝る必要はありません。
考え方を書いてもらったほうが、何を間違えているのかわかるので、
それに合わせて回答できます。

こちらの回答が理解できたのかどうか、
こちらの回答に疑問点がないかどうか、
を報告してもらえれば幸いです。

用語の使い方が適切でないように思います。例えば、タイトルの
「メモ帳からカンマ付き文字列のデータの読み込みが出来ません。」

メモ帳は、テキストファイルを作成編集するテキストエディタという
アプリケーションプログラムです。
カンマ付き文字列というのは、テキストファイル中のデータです。
メモ帳からデータを読み込むのではなく、
メモ帳で作ったテキストファイルからデータを読み込むのです。
テキストファイルは、メモ帳以外のツールで作ることができます。
メモ帳は関係ありません。

ということで、
「例えば、p[]の中身が11の場合、メモ帳に書かれた11は、」とか
「p++によって、メモ帳のカンマ「,」を扱わないようにする。」という
表現は変です。
buf の中の "11" や ',' を p が指すようになるということでしょう。
strtol関数によって10進数の整数に変換される場合、11がコンピューター内では11でない数値に変換される事がある。
10進数の整数に変換されるのではありません。
第1引数の文字列を 10進数だとみなして、それを long型の整数に変換するのです。
"11" という文字列から 11 という整数値を作り出すのです。
11 でない数値に変換される事はありません。
そこで、&pを置く事によって、文字列の11が整数に変換された場合でも、11と言う値が11以外の数値に変換されないようにする。
&p すなわち p のアドレスを第2引数で strtol に渡すことによって、
文字列 "11" を整数値 11 に変換した後の "11" の次の位置を p に
返してもらうのです。
p は buf の中の ',' を指すことになります。
その後、p++によって固定されなかった「,」は無視されて、「11,」は「11」となり、「,」FileRead_close(fh);の際に破棄される。
固定という表現が分かりませんが、p++; により、p は
buf の中で ',' の次の文字を指すようになります。
そして、strtol でそこにある数字列をまた数値に変換できるようになるのです。
FileReadclose ではファイルハンドルの先のデータが破棄されるのであって、
buf や その中の ',' が破棄されることはありません。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#45

投稿記事 by プログラマ見習い » 5年前

かずまさん。
ありがとうございます。
説明を読ませてもらいました。ああなるほど、そういう事だったのかと言う思いです。strtol関数について調べてみたのですが、かずまさんのように分かりやすく解説してくれている資料を見つける事が出来なかったので、嬉しいです。

strtol関数など、関数やソースコードにいくつか疑問点があったのですが、やはり深入りしてはいけない部分、深入りしない方がいい部分もあるのでしょうか?

次に、以前、///ここから/// ////ここまで///の部分でかずまさんが投稿してくれたソースコードで、一つ疑問点を質問します。コンパイルは2パターンとも問題なく成功しました。

以下のソースコードについてです。
ビット演算が苦手な場合

コード:

/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		int i = 0;
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = buf[i]*256 + buf[i+1];
			i += 3;
		}
	}
/////////////////////////////ここまで////////////////////////////
mapdata[y][x] = buf*256 + buf[i+1];の*256の役割がどうしても分かりませんでした。ご教示、お願いします。

アバター
usao
記事: 1889
登録日時: 11年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#46

投稿記事 by usao » 5年前

左に1bitシフトしたら値は2倍になる(という点については大丈夫か?)
左に8bitシフトしたら値は(2の8乗=256)倍になる

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#47

投稿記事 by プログラマ見習い » 5年前

usaoさん。

「左に1bitシフトしたら値は2倍になる(という点については大丈夫か?)
左に8bitシフトしたら値は(2の8乗=256)倍になる」。

 貴重なアドバイスをありがとうございます。感謝しています。

 2進数でデータが管理されている。ピンときましたと答えます。

 私は以前、かずまさんが投稿してくれた以下のソースコードについて、理解を深めるために、整数ではなく文字の場合で、2文字以外、つまり、1文字の場合、3文字の場合に変更するべきソースコードを調べていました。

コード:

/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		char *p = buf;
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = p[0]<<8 | p[1]; // ★ 先頭文字が short の上位バイト
 //☆for文でmapdata[y][x]=p[0]<<8 | p[1];の作業を繰り返しているので、ちゃんと2文字分を代入出来ている。
			p += 3; //☆','をスキップ
		}
	}
/////////////////////////////ここまで////////////////////////////
ポインタが苦手な場合

コード:

/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		int i = 0;
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = buf[i]<<8 | buf[i+1];
			i += 3; //☆','をスキップ
		}
	}
/////////////////////////////ここまで////////////////////////////
ビット演算が苦手な場合

コード:

/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		int i = 0;
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = buf[i]*256 + buf[i+1];
			i += 3; //☆','をスキップ
                        //3文字の場合はi += 4;
		}
	}
/////////////////////////////ここまで////////////////////////////
 「ビット演算が苦手な場合」については、256の役割が分からなかったのですが、usaoさんのアドバイスのおかげで、こちらも含めて、3つの全てのパターンで、データが1文字の場合と3文字の場合で、読み込んで描画する事に成功しました。
 以下にソースコードを投稿します。添付ファイルは、map3.txt map4.txtです。
 画像は、以前に投降したjpg形式の添付ファイル#2にあります。

文字の場合(1文字の場合) map3.txt
 ///ここから/// ///ここまで///は「ポインタが苦手な場合」を使用。

コード:

#include <DxLib.h>

#define MAPSIZE 32

#define HEIGHT 15
#define WIDTH 40

#define CHARA (HEIGHT * WIDTH)

struct ImageData {
	int kabe01;
	int teki0A[2];
};

struct ImageData im;

struct CharaData {
	//short kind; // ★ short: 256種類以上格納するため
        char kind; //☆1文字の場合はcharに変更。
	int anime_pattern;
	int x,y;
	int body; //体力
};

struct CharaData charadata[CHARA];
int counter; // ★ CHARA個のうち実際には counter個を使用

unsigned int g_anime_counter = 0;

//short mapdata[HEIGHT][WIDTH]; // ★ short: 256種類以上格納するため
char mapdata[HEIGHT][WIDTH]; // ☆

void MapLoad()
{
	char buf[1024];
	sprintf_s(buf, 1024, "media/map%d.txt", 3);
	int fp = FileRead_open(buf);  // ★ fp はファイルハンドル
	if (fp == 0) { printfDx("ファイル読み込みエラー"); return; }
/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		int i = 0;
		for (int x = 0; x < WIDTH; x++) {
			//mapdata[y][x] = buf[i]<<8 | buf[i+1];
                        mapdata[y][x] = buf[i]; //1文字の場合は、<<8 | buf[i+1];をなしにする。*256+buf[i+1]もなし。
			//i += 3; //☆','をスキップ
                        i+=2; //☆1文字の場合は3を2に修正
		}
	}
/////////////////////////////ここまで////////////////////////////
	FileRead_close(fp);
}

void Load()
{
	im.kabe01 = LoadGraph("media/kabe01.jpg");
	LoadDivGraph("media/teki0A.jpg", 2, 2, 1, 32, 32, im.teki0A);
}

void Init()
{
	ZeroMemory(charadata, sizeof(charadata));  // ★ ここで初期化が適切
	counter = 0;
	for (int y = 0; y < HEIGHT; y++) {
		for (int x = 0; x < WIDTH; x++) {
			//short c = mapdata[y][x];	// ★ short
                        char c = mapdata[y][x]; //☆1文字の場合はchar
			charadata[counter].kind = c;
			charadata[counter].x = x * MAPSIZE;
			charadata[counter].y = y * MAPSIZE;
			switch (c) {
			case '1': //☆
				charadata[counter].body = 1;
                                mapdata[y][x] ='0'; //☆
				counter++;
				break;
			case 'A': //☆
				charadata[counter].anime_pattern = 2;
				charadata[counter].body = 1;
                                mapdata[y][x] ='0'; //☆
				counter++;
				break;
			}

		}
	}
}

void Move()
{
	for (int i = 0; i < counter; i++) {  // ★ counter個を描画
		//short c = charadata[i].kind; // ★ short
                char c= charadata[i].kind; //☆1文字の場合はcharに変更
		switch (c) {
		case '1': //☆
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
			break;
		case 'A': //☆
			int a = g_anime_counter / 20 % charadata[i].anime_pattern;
			DrawGraph(charadata[i].x, charadata[i].y, im.teki0A[a], TRUE);
			break;
		}
		charadata[i].x = charadata[i].x - 1;
	}
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
	if (ChangeWindowMode(TRUE) != 0) return -1;
	if (DxLib_Init() != 0) return -1;
	if (SetDrawScreen(DX_SCREEN_BACK) != 0) return -1;

	MapLoad();
	Load();
	Init();

	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		if (ClearDrawScreen() != 0) return -1;
		Move();
		g_anime_counter++;
		if (ScreenFlip() != 0) return -1;
	}

	if (DxLib_End() != 0) return -1;
	return 0;
}


文字の場合(3文字の場合) map4.txt
 ///ここから/// ///ここまで///は「ポインタが苦手な場合」を使用。//の操作で「シフト演算が苦手な場合」に変更可。

コード:

#include <DxLib.h>

#define MAPSIZE 32

#define HEIGHT 15
#define WIDTH 40

#define CHARA (HEIGHT * WIDTH)

struct ImageData {
	int kabe01;
	int teki0A[2];
};

struct ImageData im;

struct CharaData {
	//short kind; // ★ short: 256種類以上格納するため
        int kind; //☆3文字の場合はint型に変更。
	int anime_pattern;
	int x,y;
	int body; //体力
};

struct CharaData charadata[CHARA];
int counter; // ★ CHARA個のうち実際には counter個を使用

unsigned int g_anime_counter = 0;

//short mapdata[HEIGHT][WIDTH]; // ★ short: 256種類以上格納するため
int mapdata[HEIGHT][WIDTH]; // ☆3文字の場合はint型に変更

void MapLoad()
{
	char buf[1024];
	sprintf_s(buf, 1024, "media/map%d.txt", 4);
	int fp = FileRead_open(buf);  // ★ fp はファイルハンドル
	if (fp == 0) { printfDx("ファイル読み込みエラー"); return; }
/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		int i = 0;
		for (int x = 0; x < WIDTH; x++) {
			//mapdata[y][x] = buf[i]<<8 | buf[i+1];
                        mapdata[y][x] = buf[i]<<16 | buf[i+1]<<8 | buf[i+2]; //3文字の場合は1ケタ目を16ビットシフト。2ケタ目を8ビットシフト。
                        //mapdata[y][x] =buf[i]*256*256+ buf[i]*256+buf[i+1]; //☆ビット演算子を使わない場合はこちら。
			//i += 3; //☆','をスキップ
                        i+=4; //☆1文字の場合は3を4に修正
		}
	}
/////////////////////////////ここまで////////////////////////////
	FileRead_close(fp);
}

void Load()
{
	im.kabe01 = LoadGraph("media/kabe01.jpg");
	LoadDivGraph("media/teki0A.jpg", 2, 2, 1, 32, 32, im.teki0A);
}

void Init()
{
	ZeroMemory(charadata, sizeof(charadata));  // ★ ここで初期化が適切
	counter = 0;
	for (int y = 0; y < HEIGHT; y++) {
		for (int x = 0; x < WIDTH; x++) {
			//short c = mapdata[y][x];	// ★ short
                        int c = mapdata[y][x]; //☆3文字の場合はint型に変更
			charadata[counter].kind = c;
			charadata[counter].x = x * MAPSIZE;
			charadata[counter].y = y * MAPSIZE;
			switch (c) {
			case '111': //☆
				charadata[counter].body = 1;
                                mapdata[y][x] ='000'; //☆
				counter++;
				break;
			case 'AAA': //☆
				charadata[counter].anime_pattern = 2;
				charadata[counter].body = 1;
                                mapdata[y][x] ='000'; //☆
				counter++;
				break;
			}

		}
	}
}

void Move()
{
	for (int i = 0; i < counter; i++) {  // ★ counter個を描画
		//short c = charadata[i].kind; // ★ short
                int c= charadata[i].kind; //☆3文字の場合はint型に変更
		switch (c) {
		case '111': //☆
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
			break;
		case 'AAA': //☆
			int a = g_anime_counter / 20 % charadata[i].anime_pattern;
			DrawGraph(charadata[i].x, charadata[i].y, im.teki0A[a], TRUE);
			break;
		}
		charadata[i].x = charadata[i].x - 1;
	}
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
	if (ChangeWindowMode(TRUE) != 0) return -1;
	if (DxLib_Init() != 0) return -1;
	if (SetDrawScreen(DX_SCREEN_BACK) != 0) return -1;

	MapLoad();
	Load();
	Init();

	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		if (ClearDrawScreen() != 0) return -1;
		Move();
		g_anime_counter++;
		if (ScreenFlip() != 0) return -1;
	}

	if (DxLib_End() != 0) return -1;
	return 0;
}
 私は、上記のソースコードを使いこなせれるようにはなりました。ただ、自分の文章で説明するまでには及んでいません。
 mapdata[y][x] = p[0]<<8 | p[1];とmapdata[y][x] = buf<<8 | buf[i+1];におけるビット演算子を用いた場合については、必要な分だけビット数をシフトさせる、「|」は、ビット単位の論理和を生成する演算子で、これによって文字のビット情報を調整する?くらいの記述しか出来ません。
 mapdata[y][x] = buf*256 + buf[i+1];については、2進数でデータが管理されている事を忘れてはならない。。2bitシフトすると2の2乗で4。8bixシフトすると2の8乗で256。16bitシフトで256×256乗くらいの記述しか出来ません。

 本トピックの主題である、メモ帳、改め、「メモ帳などで作成したテキストエディターからカンマ付のデータを読み込む」については、一応、解決のめどが立ちました。
 長くなったので、次回にそのソースコードなどを投稿する予定です。
添付ファイル
map4.txt
3文字の場合
(2.36 KiB) ダウンロード数: 416 回
map3.txt
1文字の場合
(1.18 KiB) ダウンロード数: 366 回

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#48

投稿記事 by かずま » 5年前

プログラマ見習い さんが書きました:
5年前
 mapdata[y][x] = buf[ i]*256 + buf[i+1];については、2進数でデータが管理されている事を忘れてはならない。。2bitシフトすると2の2乗で4。8bixシフトすると2の8乗で256。16bitシフトで256×256乗くらいの記述しか出来ません。
2進数は無関係です。
buf[i+1] が 0~255 の 256 種類の値を持つから、256倍しているだけです。

例えば、0~59 の 60種類の値を持つ 2つの数 m と s があったとします。
2数のままだと、その値の組をある特定の値、例えば (8, 15) と比較したい場合、
if (m == 8 && s == 15) と書かないといけません。
t = m*60 + s として、1つの数にすると、if (t == 8*60 + 15) と書けます。
8*60 + 15 は、定数式だから、case 8*60 + 15: と書くこともできます。

60 は 2のべき乗ではありません。

t = m<<6 | s; だと m や s が 6ビットの数だから、と 2進数を意識します。
この場合は、t = m*64 + s; と同じです。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#49

投稿記事 by プログラマ見習い » 5年前

 予告通り、本トピックの主題である、メモ帳、改め、「メモ帳などで作成したテキストエディターからカンマ付のデータを読み込む」の解決策について投稿します。

 皆さんのアドバイスや書籍やネットを何度か読み返して、自分が使いこなせそうな解決策を選びました。

 以下にソースコードを投稿します。
 添付ファイルはmap1.txt map2.txtです。
 画像は、以前に投降したjpg形式の添付ファイル#2にあります。

 一つは解決策1で、整数のみを利用する場合です。

解決策1 map1.txt

コード:

#include <DxLib.h>

#define MAPSIZE 32

#define HEIGHT 15
#define WIDTH  40

#define CHARA (HEIGHT * WIDTH)

struct ImageData {
	int kabe01;
	int teki0A[2];
};

struct ImageData im;

struct CharaData {
        int kind; //☆
	int anime_pattern;
	int x, y;
	int body;
};
int counter;

struct CharaData charadata[CHARA];
unsigned int g_anime_counter = 0;

int mapdata[HEIGHT][WIDTH];

void MapLoad()
{
	ZeroMemory(charadata, sizeof(charadata));

	char buf[1024];
	  //strcpy_s(buf, "media/map%d.txt",1);
        sprintf_s(buf, "media/map%d.txt",1); //☆s_printf_s関数に変更。
	int fh = FileRead_open(buf);
	if (fh == NULL) { printfDx("ファイル読み込みエラー"); return; }


//////////ここから//////////

	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fh) == -1) break;
		char *p = buf;                          // ★
		for (int x = 0; x < WIDTH; x++) {       // ★
                        mapdata[y][x] = strtol(p, &p, 10); // ★ ☆10進数。
                         //mapdata[y][x] = strtol(p, &p, 16); //☆16進数の場合
			p++; // skip ','                    // ★ ☆スキップ
		}                                       // ★
	}

//////////ここまで//////////

	FileRead_close(fh);
}

void Load()
{
	im.kabe01 = LoadGraph("media/kabe01.jpg"); //☆今回は画像形式をpngにする。
	LoadDivGraph("media/teki0A.jpg", 2, 2, 1, 32, 32, im.teki0A);
}

void Init()
{
	counter = 0;
	for (int y = 0; y < HEIGHT; y++) {
		for (int x = 0; x < WIDTH; x++) {

                        //int c=mapdata[y][x]; //☆unsignedなしでも描画された。
                        unsigned int c=mapdata[y][x]; //☆
			charadata[counter].kind = c;
			charadata[counter].x = x * MAPSIZE;
			charadata[counter].y = y * MAPSIZE;
			switch (c) {
                          case 01: // ★ ☆10進数。16進数の場合は0xを前に付ける。
				charadata[counter].body = 1;
				mapdata[y][x] =00;
				counter++;
				break;
                           case 11: // ★ ☆10進数。16進数の場合は0xを前に付ける。
				charadata[counter].anime_pattern = 2;
				charadata[counter].body = 1;
                                mapdata[y][x]=00;
				counter++;
				break;
			}
		}
	}
}

void Move()
{
	for (int i = 0; i < counter; i++) {
                //int c=charadata[i].kind;  //☆unsignedなしでも描画された。
                unsigned int c=charadata[i].kind;  //☆

		switch (c) {
                 case 01: //★☆10進数。16進数の場合は0xを前に付ける。
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
			break;

                 case 11: //★☆10進数。16進数の場合は0xを前に付ける。
			int a = g_anime_counter / 20 % charadata[i].anime_pattern;
			DrawGraph(charadata[i].x, charadata[i].y, im.teki0A[a], TRUE);
			break;
		}
		charadata[i].x = charadata[i].x - 1;
	}
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
	if (ChangeWindowMode(TRUE) != 0) return -1;
	if (DxLib_Init() != 0) return -1;
	if (SetDrawScreen(DX_SCREEN_BACK) != 0) return -1;

	MapLoad();
	Load();
	Init();

	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		if (ClearDrawScreen() != 0) return -1;
		Move();
		g_anime_counter++;
		if (ScreenFlip() != 0) return -1;
	}

	if (DxLib_End() != 0) return -1;
	return 0;
}


 上記は、strtol関数に魅力を感じた事が主な理由です。
 かずまさんがstrtol関数について詳細に解説してくれたおかげで、strtol関数や、コンピュータ内部で行われている処理について、理解を深める事が出来ました。本当にありがとうございます。



 次は解決策2で、整数の他の2ケタの文字を利用する場合です。

解決策2 map2.txt

コード:

#include <DxLib.h>

#define MAPSIZE 32

#define HEIGHT 15
#define WIDTH 40

#define CHARA (HEIGHT * WIDTH)

struct ImageData {
	int kabe01;
	int teki0A[2];
};

struct ImageData im;

struct CharaData {
	short kind; // ★ short: 256種類以上格納するため
        //int kind; //☆int型でも可。但し、合わせる事。
	int anime_pattern;
	int x,y;
	int body; //体力
};

struct CharaData charadata[CHARA];
int counter; // ★ CHARA個のうち実際には counter個を使用

unsigned int g_anime_counter = 0;

short mapdata[HEIGHT][WIDTH]; // ★ short: 256種類以上格納するため
//int mapdata[HEIGHT][WIDTH]; //☆int型でも可。但し、合わせる事。

void MapLoad()
{
	char buf[1024];
	sprintf_s(buf, 1024, "media/map%d.txt", 2);
	int fp = FileRead_open(buf);  // ★ fp はファイルハンドル
	if (fp == 0) { printfDx("ファイル読み込みエラー"); return; }
/////////////////////////////ここから////////////////////////////
	for (int y = 0; y < HEIGHT; y++) {
		if (FileRead_gets(buf, 1024, fp) == -1) break;
		char *p = buf;
		for (int x = 0; x < WIDTH; x++) {
			mapdata[y][x] = p[0]<<8 | p[1]; // ★ 先頭文字が short の上位バイト
 //☆ <<はビット単位のシフト演算子。|はビット単位の論理和を生成する演算子。
			p += 3; //☆','をスキップ
		}
	}
/////////////////////////////ここまで////////////////////////////
	FileRead_close(fp);
}

void Load()
{
	im.kabe01 = LoadGraph("media/kabe01.jpg");
	LoadDivGraph("media/teki0A.jpg", 2, 2, 1, 32, 32, im.teki0A);
}

void Init()
{
	ZeroMemory(charadata, sizeof(charadata));  // ★ ここで初期化が適切
	counter = 0;
	for (int y = 0; y < HEIGHT; y++) {
		for (int x = 0; x < WIDTH; x++) {
			short c = mapdata[y][x];	// ★ short
                        //int c=mapdata[y][x]; //int型でも可。但し、合わせる事。
			charadata[counter].kind = c;
			charadata[counter].x = x * MAPSIZE;
			charadata[counter].y = y * MAPSIZE;
			switch (c) {
			case '11':
				charadata[counter].body = 1;
                                mapdata[y][x] ='00'; //
				counter++;
				break;
			case 'AA':
				charadata[counter].anime_pattern = 2;
				charadata[counter].body = 1;
                                mapdata[y][x] ='00';
				counter++;
				break;
			}

		}
	}
}

void Move()
{
	for (int i = 0; i < counter; i++) {  // ★ counter個を描画
		short c = charadata[i].kind; // ★ short
                //int c=charadata[i].kind; //☆int型でも可。但し、合わせる事。
		switch (c) {
		case '11':
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
			break;
		case 'AA':
			int a = g_anime_counter / 20 % charadata[i].anime_pattern;
			DrawGraph(charadata[i].x, charadata[i].y, im.teki0A[a], TRUE);
			break;
		}
		charadata[i].x = charadata[i].x - 1;
	}
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
	if (ChangeWindowMode(TRUE) != 0) return -1;
	if (DxLib_Init() != 0) return -1;
	if (SetDrawScreen(DX_SCREEN_BACK) != 0) return -1;

	MapLoad();
	Load();
	Init();

	while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) {
		if (ClearDrawScreen() != 0) return -1;
		Move();
		g_anime_counter++;
		if (ScreenFlip() != 0) return -1;
	}

	if (DxLib_End() != 0) return -1;
	return 0;
}
 結果として、今回の解決策では、両者とも、かずまさんのアドバイスを選ぶ事になりました。出来る事なら、他の皆さんのも選びたかったのですが、残念ながら、使いこなせませんでした。

 本トピックでの私の質問については、上記のソースコードを以て、解決とさせていただきます。
 自分の中では理解が深まったとは思っていても、自分では気づいていない理解し間違いがあるのではないかと言う不安、sscanf_sを利用した場合などの他の方法も試してみたい、また、上記の解決策を今の自分では文章で表現するのが難しいなど、心残りが無きにしも非ずです。
 しかし、これ以上本トピックをを長引かせるわけにもいかない事、これ以上皆さんに負担をかけてしまう事に申し訳なく思っている事、深入りしすぎる所があった事、本トピックの趣旨から逸れる分野に及びかねない部分があった事、そして、当初の課題である「メモ帳などで作成したテキストエディターからカンマ付のデータを読み込む」ためのソースコードを使いこなす事には成功している事が主な理由です。

 上記の通り、最終的にかずまさんのアドバイスに偏ったアドバイスを選んだのですが、他の皆さんのアドバイスもまた、私が今まで理解が足りなかったプログラミングについての理解を深める事に繋がりました。
 皆さん、本当にありがとうございます。
添付ファイル
map1.txt
解決策1
(1.77 KiB) ダウンロード数: 356 回

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#50

投稿記事 by プログラマ見習い » 5年前

map2.txtの添付に失敗したので、添付します。
添付ファイル
map2.txt
解決策2
(1.77 KiB) ダウンロード数: 375 回

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#51

投稿記事 by かずま » 5年前

プログラマ見習い さんが書きました:
5年前
 予告通り、本トピックの主題である、メモ帳、改め、「メモ帳などで作成したテキストエディターからカンマ付のデータを読み込む」の解決策について投稿します。
メモ帳はテキストエディタを作成しません。
メモ帳はテキストエディタです。
テキストエディタはテキストファイルを作成します。
今回の問題にメモ帳は無関係です。

「ファイルから、カンマ付きのデータを読み込む」となぜ言わないのでしょうか?

コード:

		switch (c) {
                 case 01: //★☆10進数。16進数の場合は0xを前に付ける。
			DrawGraph(charadata[i].x, charadata[i].y, im.kabe01, TRUE);
01 は 10進数ではありません。
C のソースプログラムでは、0 で始まる数は 8進数です。
00, 01, 02, ... 07 までは書けますが、08, 09 はエラーです。

ソースの修正部分のインデント(字下げ) が変です。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#52

投稿記事 by プログラマ見習い » 5年前

かずまさん。
ご指摘、ありがとうございます。危うく、間違ったまま理解してしまう所でした。

「ファイルから、カンマ付きのデータを読み込む」について。
すみません。初歩的な間違いをしていました。メモ帳で書いていたので、いまだにメモ帳に気を取られていた事が原因です。「ファイルから、カンマ付きのデータを読み込む」に変更します。

「01 は 10進数ではありません。C のソースプログラムでは、0 で始まる数は 8進数です。00, 01, 02, ... 07 までは書けますが、08, 09 はエラーです。」について。
驚きです。そこは初めて知りました。手元にある入門書を読み返しても、そこまでは書いてありませんでした。ネットで検索すると、ありました。01,02だけでなく、8進数の12はC言語では012と表記する事も分かりました。
となると、解決策1のコンセプトでは、ファイルのデータの見た目じょうの問題をどうするかの問題が出てきます。
と言うのも、1~9までは01~09、2ケタなら10~と、2ケタでまとめた方が見た目が見やすいのですが、見た目を重視すると、16進数以外に選択肢がなくなります。16進数に合わせて、訂正します。

「ソースの修正部分のインデント(字下げ) が変です。」について。
私は、半角1個分の方が、横スクロールバーを動かす手間が少なくて済むので、使いやすい感覚があります。インテンドが不自然なのは、コピペと修正を繰り返した結果です。
ただ、インテンド調整に関する認識が自分には不足しているとしても、当の自分にはまだピンと来ていないと言うのが本音です。
もう少し、詳しい説明をお願いします。

「ファイルから、カンマ付きのデータを読み込む」事に気を取られていたとは言え、初歩的な間違いをたびたび起こしてしまって、皆さん、本当に申し訳ございません。

かずま

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#53

投稿記事 by かずま » 5年前

プログラマ見習い さんが書きました:
5年前
「01 は 10進数ではありません。C のソースプログラムでは、0 で始まる数は 8進数です。00, 01, 02, ... 07 までは書けますが、08, 09 はエラーです。」について。
驚きです。そこは初めて知りました。手元にある入門書を読み返しても、そこまでは書いてありませんでした。ネットで検索すると、ありました。01,02だけでなく、8進数の12はC言語では012と表記する事も分かりました。
となると、解決策1のコンセプトでは、ファイルのデータの見た目じょうの問題をどうするかの問題が出てきます。
と言うのも、1~9までは01~09、2ケタなら10~と、2ケタでまとめた方が見た目が見やすいのですが、見た目を重視すると、16進数以外に選択肢がなくなります。16進数に合わせて、訂正します。
0で始まるのが 8進数なのは、C のソースコード上だけの話です。
case 09: や n = 09; などはエラーです。

しかし、プログラム内部の文字列データは、0 で始まろうが、0 が無かろうが
指定した進数で処理を行います。

n = strtol("09", NULL, 10); とあった場合、n は 9 になります。

n = 012; だと n の値は 10 ですが、
n = strtol("012", NULL, 10); の場合、n の値は 12 になります。
n = strtol("012", NULL, 16); の場合、n の値は 18 になります。
n = strtol("012", NULL, 8); の場合、n の値は 10 になります。

scanf("%d", &n); で入力が 012 でも n には 12 が入ります。

n = strtol("012", NULL, 0); のように基数に 0 を指定すると、
数字の列が 0 で始まっているか、0x で始まっているか、そうでないかで
8進数、16進数、10進数だと解釈します。

scanf も %d は 10進、%x は 16進、%o は 8進の入力ですが、
%i だと、入力の先頭の 0 または 0x の有無によって異なる変換をします。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#54

投稿記事 by プログラマ見習い » 5年前

かずまさん。
「case 09: や n = 09; などはエラーです。」
「n = strtol("09", NULL, 10); とあった場合、n は 9 になります。」
「なるほど、そういう事だったのか。」と言う思いです。
貴重なアドバイス、本当にありがとうございます。感謝しています。

プログラマ見習い
記事: 44
登録日時: 5年前

Re: メモ帳からカンマ付き文字列のデータの読み込みが出来ません。

#55

投稿記事 by プログラマ見習い » 5年前

解決策1の部分の間違い部分を訂正します。
 10進数で読み込む場合。
Init関数とMove関数のcase 01:の部分
 case 1: //01を1に訂正。
Init関数の2か所のmapdata[y][x]=00;の部分
 mapdata[y][x]=0; //00を0に訂正。

返信

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