ページ 11

ゲーム

Posted: 2007年1月19日(金) 16:24
by 霧子
こんにちは。また分からない問題がでましたので、質問しに来ました。
まず、
#include <stdio.h>
#define VT 10
#define HZ 10

int next [VT][HZ];
int now [VT][HZ]={{0,0,0,0,0,0,0,0,0,0},
                  {0,0,0,0,0,0,0,0,0,0},
                  {0,0,0,0,0,0,0,0,0,0},
                  {0,0,0,0,0,0,0,0,0,0},
                  {0,0,0,0,0,1,0,0,0,0},
                  {0,0,0,0,0,0,1,0,0,0},
                  {0,0,0,0,0,1,0,0,0,0},
                  {0,0,0,0,0,0,0,0,0,0},
                  {0,0,0,0,0,0,0,0,0,0},
                  {0,0,0,0,0,0,0,0,0,0}};
void calc_cell(int v,int h){
   int work;
   work=now[(v+VT-1)%VT][(h+HZ-1)%HZ]+now[(v+VT-1)%VT][(h+HZ)%HZ]+now[(v+VT-1)%VT][(h+HZ+1)%HZ]
            +now[(v+VT)%VT][(h+HZ-1)%HZ]                         +now[(v+VT)%VT][(h+HZ+1)%HZ]
            +now[(v+VT+1)%VT][(h+HZ-1)%HZ]+now[(v+VT+1)%VT][(h+HZ)%HZ]+now[(v+VT+1)%VT][(h+HZ+1)%HZ];


    next[v][h]==0;
    if(now [v][h]==0 && work==3)next[v][h]==1;
       if(now [v][h]== 1 && work==2 || work == 3) next[v][h]==1;
   }


   void copystatus(void) {
  int v,h;
    for( v=0;v<VT;v++)  
        for(h=0;h<HZ;h++) 
            now[v][h]=next[v][h];
    }

  

   void showstatus(void){  
    int v,h; 
     for(v = 0; v< VT; v++) {
        for(h= 0; h<HZ; h++) 
           if(now[v][h]==1)printf("*");
            else printf(" ");
         printf("\n");
     }                       
   }

void cls() { 
   printf("\033[2J");
    } 

main() { 
    int v,h;char com='c';

    while(com!='q'){
        cls();showstatus();
        for(v=0;v<VT;v++)
           for(h=0;h<HZ;h++)calc_cell(v,h);
         copystatus();
     printf("続ける:n セーブ:s ロード:l 戻る:r 終了:q\n");
     scanf("%s",&com);
    }    
 }
といったライフゲームをつくりました。

これを、

セーブとロードと1つ前に戻るを可能にしたいのです。



ファイルの入出力をつかって

FILE *fout;

fout=fopen("diskfile","w");でセーブ、wをrにしてロードをつくるようなことを考えているのですが、できませんでした。

それと、1つ戻るは今のところ考えつきません。逆のことをやるようにするとは思うのですが。



いろいろ調べてはみたのですが、分かりませんでした。すみませんが、どなたか教えてください。お願いします。

Re:ゲーム

Posted: 2007年1月19日(金) 18:01
by バグ
1つ戻るだけでいいのならば、変化する1つ前の状態を別の領域にコピーしておけばいいと思います。
しかし、機能追加よりも先にバグ取りをした方がいいのではないでしょうか?ザッと見ただけでも、かなりの数のバグがあるようですし…このままではコンパイルが通らないはずです。

Re:ゲーム

Posted: 2007年1月19日(金) 18:10
by 霧子
バグさん返信ありがとうございます。
急いでつくったもので(^^;。バグがありますか、ちょっと考えてみます。

Re:ゲーム

Posted: 2007年1月19日(金) 19:14
by 霧子
多分バグ直ったと思うのですが・・・。

1つ戻るだけでいいのならば、変化する1つ前の状態を別の領域にコピーとは、どうすればよいのでしょうか?

Re:ゲーム

Posted: 2007年1月19日(金) 23:18
by box
> 1つ戻るだけでいいのならば、変化する1つ前の状態を別の領域にコピーとは、どうすればよいのでしょうか?

配列nowと同じ大きさの領域(名前の例:prev)を用意し、
nowからprevへの全要素コピーを行なえばよいです。

全要素コピー直後は、prevとnowの内容は同じです。

次に、一手進めてnowの内容を書き換えると、
prevには直前の状態が、nowには現在の状態が入ります。

ここで、一手前へ戻りたければ、prevからnowへの
全要素コピーを行なえばよいです。

Re:ゲーム

Posted: 2007年1月20日(土) 14:00
by 霧子
boxさん返信ありがとうございます。

自分なりに考えてみたのが、mainの中だけかえて
main() {
    FILE  *fp,*fin,*prev;
    int v,h,x;
    char com='c';

    while(com!='q'){
        cls();showstatus();
        for(v=0;v<VT;v++)
           for(h=0;h<HZ;h++)calc_cell(v,h);
         copystatus();
     printf("続ける:n セーブ:s ロード:l 戻る:r 終了:q\n");
     scanf("%s",&com);

         prev=fopen("file2","w");
          x=int now [VT][HZ];
          fprintf(fp, "%d\n",x);
         fclose(fp);exit(0);

        if(com==s){
                   fp=fopen("file1","w");
                     x=int now [VT][HZ];
                     fprintf(fp, "%d\n",x);
                   fclose(fp);exit(0);
                                              }
        if(com==l){
                   fin=fopen("file1","r");                  
          fscanf(fin,"%d",&x)
                   fclose(fin);exit(0);
                   printf("%d\n",x);
                                             }
        if(com==r){

                   fin=fopen("file2","r");                  
          fscanf(fin,"%d",&x)
                   fclose(fin);exit(0);
                   printf("%d\n",x);
                                             }
    }    
 }
としたのですが、うまくいっていないと思います。(実はすぐコンパイルできる環境がないので確かめられていないのですが)
すみませんがどなたか、どのように直したらよいのか。また正解はどういったものか教えてください。お願いします。
ついでにexit(0);はある本をよんだらのっていましたので、終了するために必要だと思いいれておきました。あっているのでしょうか?

Re:ゲーム

Posted: 2007年1月21日(日) 00:06
by 霧子
入力と出力の部分を
x=int now [VT][HZ];
fprintf(fp, "%d\n",x);
と無理やりしたのはまずいでしょうねやっぱり。
boxさんが指摘してくれたように全要素コピーをしたいところですが・・・どうすればいいんでしょう?
なんか方法があるのでしょうか。それを出力もできるのでしょうか。
未だ、思考中です。

Re:ゲーム

Posted: 2007年1月21日(日) 00:56
by 管理人
こんにちは。
急いで読んだので、理解落ちがあると思いますが、その時はすみません。

えぇと、コピーした配列の中身をfprintfで書き出したいということですか?

それでしたら2重ループをつかって

for(i=0;i<VT;i++){
  for(j=0;j<HZ;j++){
    fprintf(fp, "%d ",x[j]);
  }
  fprintf(fp,"\n");
}

こう書いてみてはいかがでしょうか?

もし

int x[5][5]={
{1,2,3,4,5},
{2,3,4,5,6},
{3,4,5,6,7},
{4,5,6,7,8},
{5,6,7,8,9}};


このようにはいっているxでしたら書き出したファイルは
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9


このようになっているはずです。

fin=fopen("file1","r");
fscanf(fin,"%d",&x)
fclose(fin);
exit(0);
printf("%d\n",x);

それとこのように書くと、最後のprintfが実行されないように思うのですが。

exitを書くとそこで強制終了しますからその後の処理は行われません。

行いたいことが違ってたらすみません・・

Re:ゲーム

Posted: 2007年1月21日(日) 02:03
by 霧子
管理人さん返信ありがとうございます。

いろいろのべましたが、結局は最初に述べたプログラムの
「セーブとロードと1つ前に戻るを
printf("続ける:n セーブ:s ロード:l 戻る:r 終了:q\n");
とあるように
キーボードでs押したらセーブ、l押したらロード、r押したら戻る
を可能にしたい」のです。

Re:ゲーム

Posted: 2007年1月21日(日) 05:20
by 管理人
なるほど、ライフゲームというゲームがあるんですね、知りませんでした・・。

ちょろっと解説をみたところルールがよくわかりません:;

時間の有る時よくみておきます。

とりあえず1つ前に戻るのはboxさんのおっしゃるとおりでいいのではないでしょうか。

ファイル書き出し、読み込みはスキャン、プリントそれぞれ2重ループを使って行いましょう。

正解を書いてあげられたらいいのですけど、、;

ちょっと時間を見つけて書いてみますね。(期待せずに待っててください;

Re:ゲーム

Posted: 2007年1月21日(日) 13:15
by 霧子
管理人さんありがとうございます。

自分も足りない頭で考え中です。

Re:ゲーム

Posted: 2007年1月21日(日) 23:30
by バグ
ライフゲームの基本的なルールを調べてみました。

1:調査マスが死んでいて(0の状態)、周囲8マスの内の3マスが生きて(1の状態)いた場合に、次世代に誕生(1の状態)する。

2:調査マスが生きていて、周囲8マスの内の2マスか3マスが生きている場合は、次世代も継続して生き続ける。

3:それ以外の条件では死ぬ。

なんだか面白そうなので、コンソールアプリでパターンエディタも一緒に作ってみようかな?(^-^)

クラス化すれば、楽に作れる気がします…

どうも、C++から入った人間なせいか、C言語のみで組むのが苦手になってしまっているようです…(;^_^A

Re:ゲーム

Posted: 2007年1月22日(月) 23:13
by バグ
1つ戻るとか、保存機能の無い簡単なライフゲームを作ってみました(^-^)

Re:ゲーム

Posted: 2007年1月23日(火) 00:25
by 管理人
http://dixq.net/game.html

バグさんがおつくりになったゲームをアップロードしておきました^^

Re:ゲーム

Posted: 2007年1月23日(火) 18:39
by 霧子
すごいですね。バグさん。
自分にはなにで作られたか分かりませんが。

自分は結局セーブ、ロード、戻るがまだできていない状況です。なんか単純そうな気がするんですがうまくいきません。

Re:ゲーム

Posted: 2007年1月24日(水) 22:40
by 霧子
>ファイル書き出し、読み込みはスキャン、プリントそれぞれ2重ループを使って行いましょう。
多分 whileの中の
cls();showstatus();
for(v=0;v<VT;v++)
for(h=0;h<HZ;h++)calc_cell(v,h);
copystatus();
で映し出したものを読み込みすると思うのですが。
でもその前の数字を読み込んでおいて書き出しはこの関数を通のですか?

なんか混乱してきています。

もうすぐ締め切りなので明日の朝までできなければ、残念ながら諦めたいと思います。

Re:ゲーム

Posted: 2007年1月25日(木) 02:04
by 管理人
すみません、とりあえず落ち着きましたので、今から作りますね。

Re:ゲーム

Posted: 2007年1月25日(木) 02:08
by 霧子
いえいえ、管理人さん謝る必要はないですよ。むしろこちらが感謝です。

>今から作りますね。
本当にありがとうございます。助かります。

Re:ゲーム

Posted: 2007年1月25日(木) 03:19
by 管理人
遅くなりました。最大限お書きになったプログラムをいかしたつもりです。

とりあえず、出来たと思うので、実行して自分の行いたい事とあってるか確認してください。
#include <stdio.h>
#include <stdlib.h>

#define VT 10
#define HZ 10

int prev [VT][HZ];
int next [VT][HZ];
int now [VT][HZ]={{0,0,0,0,0,0,0,0,0,0},
					{0,0,0,1,1,1,0,0,0,0},
					{0,0,0,0,1,0,1,0,0,0},
					{0,0,0,1,1,0,0,0,0,0},
					{0,0,0,0,0,1,0,1,0,0},
					{0,0,0,1,0,0,1,1,0,0},
					{0,0,1,1,0,1,0,1,0,0},
					{0,1,0,1,0,1,0,1,1,0},
					{0,1,0,1,1,0,1,1,0,0},
					{0,1,0,0,0,1,0,0,1,0}};
void calc_cell(){
	int v,h,work;
	for(v=0;v<VT;v++){
		for(h=0;h<HZ;h++){
			work=now[(v+VT-1)%VT][(h+HZ-1)%HZ]+now[(v+VT-1)%VT][(h+HZ)%HZ]+now[(v+VT-1)%VT][(h+HZ+1)%HZ]
			     +now[(v+VT)%VT][(h+HZ-1)%HZ]			       +now[(v+VT)%VT][(h+HZ+1)%HZ]
			     +now[(v+VT+1)%VT][(h+HZ-1)%HZ]+now[(v+VT+1)%VT][(h+HZ)%HZ]+now[(v+VT+1)%VT][(h+HZ+1)%HZ];
			next[v][h]=0;
			if((now [v][h]==0 && work==3) || (now [v][h]== 1 && work==2 || work == 3))
				next[v][h]=1;
		}
	}
}

void copystatus(void) {
	int v,h;
	for( v=0;v<VT;v++){
		for(h=0;h<HZ;h++){
			prev[v][h]=now [v][h];	
			now [v][h]=next[v][h];
		}
	}
}

void copy_prev_status(void){
	int v,h;
	for( v=0;v<VT;v++)
		for(h=0;h<HZ;h++)
			now [v][h] = prev[v][h];
}

void showstatus(void){	
	int v,h; 
	for(v = 0; v< VT; v++) {
		for(h= 0; h<HZ; h++){
			if(now[v][h]==1)
				printf("■");
			else
				printf("□");
		}
		printf("\n");
	}
	printf("\n\n");
	return;
}

void read(){
	int v,h;
	FILE *fp;
	if((fp=fopen("file1.txt","r"))==NULL){
		printf("error");
		exit(9);
	}
	for(v=0;v<VT;v++)
		for(h=0;h<HZ;h++)
			fscanf(fp,"%d\n",&now[v][h]);
	fclose(fp);
	return;
}

void save(){
	int v,h;
	FILE *fp;
	if((fp=fopen("file1.txt","w"))==NULL){
		printf("error");
		exit(9);
	}
	for(v=0;v<VT;v++)
		for(h=0;h<HZ;h++)
			fprintf(fp,"%d\n",now[v][h]);
	fclose(fp);
	return;
}

int main() {
	char com='c';
	while(com!='q'){
		system("cls");
		if(com!='r' && com!='s' && com!='l'){
			calc_cell();
			copystatus();
		}
		showstatus();
		printf("続ける:n\nセーブ:s\nロード:l\n戻る:r\n終了:q\n");
		scanf("%s",&com);
		if(com=='s')
			save();
		if(com=='r')
			copy_prev_status();
		if(com=='l')
			read();
	}	
	return 0;
}

http://dixq.net/etc/file1.txt

これを実行するフォルダにいれて実行してください。

説明は以下書きます。

Re:ゲーム

Posted: 2007年1月25日(木) 03:29
by 管理人
注釈を書きました。解らないところがあれば聞いてください。
#include <stdio.h>
#include <stdlib.h>

#define VT 10
#define HZ 10

int prev [VT][HZ];
int next [VT][HZ];
int now [VT][HZ]={{0,0,0,0,0,0,0,0,0,0},
					{0,0,0,1,1,1,0,0,0,0},
					{0,0,0,0,1,0,1,0,0,0},
					{0,0,0,1,1,0,0,0,0,0},
					{0,0,0,0,0,1,0,1,0,0},
					{0,0,0,1,0,0,1,1,0,0},
					{0,0,1,1,0,1,0,1,0,0},
					{0,1,0,1,0,1,0,1,1,0},
					{0,1,0,1,1,0,1,1,0,0},
					{0,1,0,0,0,1,0,0,1,0}};

//ここの処理は変わっていません。if文をちょっとスマートに書いただけです。
void calc_cell(){
	int v,h,work;
	for(v=0;v<VT;v++){
		for(h=0;h<HZ;h++){
			work=now[(v+VT-1)%VT][(h+HZ-1)%HZ]+now[(v+VT-1)%VT][(h+HZ)%HZ]+now[(v+VT-1)%VT][(h+HZ+1)%HZ]
			     +now[(v+VT)%VT][(h+HZ-1)%HZ]			       +now[(v+VT)%VT][(h+HZ+1)%HZ]
			     +now[(v+VT+1)%VT][(h+HZ-1)%HZ]+now[(v+VT+1)%VT][(h+HZ)%HZ]+now[(v+VT+1)%VT][(h+HZ+1)%HZ];
			next[v][h]=0;
			if((now [v][h]==0 && work==3) || (now [v][h]== 1 && work==2 || work == 3))
				next[v][h]=1;
		}
	}
}

//コピーステータスでは、nowに計算結果を格納すると同時に、prev配列、つまり前回の状態を記憶する配列に
//今の状態を記憶します。1つ戻す操作を行う時に、prevをnowにいれたらいいわけです。
//これだと1つしか戻せず、2つ以上戻したい時は3次元配列を使うと良いでしょう。
void copystatus(void) {
	int v,h;
	for( v=0;v<VT;v++){
		for(h=0;h<HZ;h++){
			prev[v][h]=now [v][h];	
			now [v][h]=next[v][h];
		}
	}
}

//1つ前に戻す操作を実現します。prevの中身をnowにいれています。
void copy_prev_status(void){
	int v,h;
	for( v=0;v<VT;v++)
		for(h=0;h<HZ;h++)
			now [v][h] = prev[v][h];
}

//表示を行います。
void showstatus(void){	
	int v,h; 
	for(v = 0; v< VT; v++) {
		for(h= 0; h<HZ; h++){
			if(now[v][h]==1)
				printf("■");
			else
				printf("□");
		}
		printf("\n");
	}
	printf("\n\n");
	return;
}


//ロード機能です。
void read(){
	int v,h;
	FILE *fp;
	//ファイルの情報ポインタをfpに格納します。このポインタがnullならエラーを表示し、
	//即座に終了します。
	if((fp=fopen("file1.txt","r"))==NULL){
		printf("error");
		exit(9);
	}
	//1行に1データずつあるので、その形式で読み込みます。
	for(v=0;v<VT;v++)
		for(h=0;h<HZ;h++)
			fscanf(fp,"%d\n",&now[v][h]);
	//ファイルを閉じます。
	fclose(fp);
	return;
}

//セーブ機能です。
void save(){
	int v,h;
	FILE *fp;
	if((fp=fopen("file1.txt","w"))==NULL){
		printf("error");
		exit(9);
	}
	//1行に1データずつ記録します。
	for(v=0;v<VT;v++)
		for(h=0;h<HZ;h++)
			fprintf(fp,"%d\n",now[v][h]);
	fclose(fp);
	return;
}

int main() {
	char com='c';
	while(com!='q'){
		//画面のバッファをクリアし、画面の情報を消します。
		system("cls");
		//前回続ける以外の操作がされた時には計算を実行しません。
		if(com!='r' && com!='s' && com!='l'){
			calc_cell();
			copystatus();
		}
		//表示します。
		showstatus();
		printf("続ける:n\nセーブ:s\nロード:l\n戻る:r\n終了:q\n");
		scanf("%s",&com);
		if(com=='s')
			save();
		if(com=='r')
			copy_prev_status();
		if(com=='l')
			read();
	}
	return 0;
}

Re:ゲーム

Posted: 2007年1月25日(木) 05:14
by 霧子
管理人さん本当にありがとうございます。お疲れ様です。
多分あっていると思います。
わざわざ注釈までつけてくださって助かります。
ありがとうございました。

Re:ゲーム

Posted: 2007年1月25日(木) 05:27
by 管理人
私のような人間が書くソースですからあっている保証はないですし、もっとスマートに書く方法もあるはずです^^;
ですのでもし提出されるんでしたらしっかり確認してくださいね!

人の書いたプログラムってホントみにくいですからどこかわからないとこがあったら何でも聞いてくださいね~☆

ライフゲームってゲーム知らなかったので一つ新しいゲームが知れてよかったです^^

Re:ゲーム

Posted: 2007年1月25日(木) 05:29
by 管理人
あ、注釈に書き忘れましたが、

強制終了をさせるexit関数は、

#include <stdlib.h>

を最初にかかないと使えません。これはstdlib.hっていう説明書の中にexit関数の使い方が書いてあるので

これをインクルード(直訳=含む)しないと機械がわからないから使えないんだって思ってください。

Re:ゲーム

Posted: 2007年1月25日(木) 10:25
by バグ
変数workの計算式ですが、このままでは霧子さんの思う動きにならないと思います。
VTとHZは変数の個数であって、配列自体は[0]~[VT -1](今回は[0]~[9])、[0]~[HZ - 1](今回は[0]~[9])までしか用意されていませんので、今のままの計算式では、本来0~9の間をループしなければいけないのに、0以下になった場合は8に、10より大きくになった場合に0に戻るので、本来参照してはいけないはずの11番目の[10]にアクセスしてしまっていて危険です。
計算式自体は間違っていないので、座標を求めている部分を…

a % b

から

a % ( b - 1 )

に変更するだけで対応できると思います。

でも、この座標計算式は勉強になりました。上下左右にループさせる時には便利ですよね(^-^)

Re:ゲーム

Posted: 2007年1月25日(木) 15:58
by 管理人
計算式は特に見ていませんでした^^;
ループにあまりが利用できるのは便利ですね^^

Re:ゲーム

Posted: 2007年1月25日(木) 16:29
by バグ
実は、私も霧子さんのソースをとりあえず動くようにしてみたのですが、どうにもおかしな動きをしていたので、解析してみると…前記のような理由だったんです(^_^;)

Re:ゲーム

Posted: 2007年1月25日(木) 17:18
by 霧子
バグさん、管理人さんいろいろと補足説明ありがとうございます。

バグさんも動くようにして下さっていたんですね。感謝です。

Re:ゲーム

Posted: 2007年1月25日(木) 20:30
by フリオ
 
>変数workの計算式ですが、このままでは霧子さんの思う動きにならないと思います。

 "work"の計算式は、管理人さんや、霧子さんの方法であってます。

VT = 10、v = 9 のとき、 (v + VT + 1) % VT は、
(9 + 10 + 1) % 10 = 20 % 10 = 0
また、VT = 10、 v = 0 のときは、
(0 + 10 - 1) % 10 = 9 % 10 = 9
で、9 の次は 0 に、0 の前は 9 になります。

VT で割った余りは、0 ~ (VT - 1)になるので、
[(v + VT + 1) % VT]は、[0] ~ [VT - 1]であり、[VT]にはなりません。
HZについても同じです。

おかしな動きは、他に原因があるのではないでしょうか。
 

Re:ゲーム

Posted: 2007年1月26日(金) 01:13
by 管理人
う~ん、ライフゲーム自体はじめてみたもので^^;

Re:ゲーム

Posted: 2007年1月26日(金) 18:11
by 霧子
フリオさんご指摘ありがとうございます。

なかなか、難しいものですね。