ゲーム

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

ゲーム

#1

投稿記事 by 霧子 » 18年前

こんにちは。また分からない問題がでましたので、質問しに来ました。
まず、
#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:ゲーム

#2

投稿記事 by バグ » 18年前

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

霧子

Re:ゲーム

#3

投稿記事 by 霧子 » 18年前

バグさん返信ありがとうございます。
急いでつくったもので(^^;。バグがありますか、ちょっと考えてみます。

霧子

Re:ゲーム

#4

投稿記事 by 霧子 » 18年前

多分バグ直ったと思うのですが・・・。

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

box

Re:ゲーム

#5

投稿記事 by box » 18年前

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

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

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

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

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

霧子

Re:ゲーム

#6

投稿記事 by 霧子 » 18年前

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:ゲーム

#7

投稿記事 by 霧子 » 18年前

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

管理人

Re:ゲーム

#8

投稿記事 by 管理人 » 18年前

こんにちは。
急いで読んだので、理解落ちがあると思いますが、その時はすみません。

えぇと、コピーした配列の中身を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:ゲーム

#9

投稿記事 by 霧子 » 18年前

管理人さん返信ありがとうございます。

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

管理人

Re:ゲーム

#10

投稿記事 by 管理人 » 18年前

なるほど、ライフゲームというゲームがあるんですね、知りませんでした・・。

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

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

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

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

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

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

霧子

Re:ゲーム

#11

投稿記事 by 霧子 » 18年前

管理人さんありがとうございます。

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

バグ

Re:ゲーム

#12

投稿記事 by バグ » 18年前

ライフゲームの基本的なルールを調べてみました。

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

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

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

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

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

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

バグ

Re:ゲーム

#13

投稿記事 by バグ » 18年前

1つ戻るとか、保存機能の無い簡単なライフゲームを作ってみました(^-^)

管理人

Re:ゲーム

#14

投稿記事 by 管理人 » 18年前

http://dixq.net/game.html

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

霧子

Re:ゲーム

#15

投稿記事 by 霧子 » 18年前

すごいですね。バグさん。
自分にはなにで作られたか分かりませんが。

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

霧子

Re:ゲーム

#16

投稿記事 by 霧子 » 18年前

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

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

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

管理人

Re:ゲーム

#17

投稿記事 by 管理人 » 18年前

すみません、とりあえず落ち着きましたので、今から作りますね。

霧子

Re:ゲーム

#18

投稿記事 by 霧子 » 18年前

いえいえ、管理人さん謝る必要はないですよ。むしろこちらが感謝です。

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

管理人

Re:ゲーム

#19

投稿記事 by 管理人 » 18年前

遅くなりました。最大限お書きになったプログラムをいかしたつもりです。

とりあえず、出来たと思うので、実行して自分の行いたい事とあってるか確認してください。
#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:ゲーム

#20

投稿記事 by 管理人 » 18年前

注釈を書きました。解らないところがあれば聞いてください。
#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:ゲーム

#21

投稿記事 by 霧子 » 18年前

管理人さん本当にありがとうございます。お疲れ様です。
多分あっていると思います。
わざわざ注釈までつけてくださって助かります。
ありがとうございました。

管理人

Re:ゲーム

#22

投稿記事 by 管理人 » 18年前

私のような人間が書くソースですからあっている保証はないですし、もっとスマートに書く方法もあるはずです^^;
ですのでもし提出されるんでしたらしっかり確認してくださいね!

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

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

管理人

Re:ゲーム

#23

投稿記事 by 管理人 » 18年前

あ、注釈に書き忘れましたが、

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

#include <stdlib.h>

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

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

バグ

Re:ゲーム

#24

投稿記事 by バグ » 18年前

変数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:ゲーム

#25

投稿記事 by 管理人 » 18年前

計算式は特に見ていませんでした^^;
ループにあまりが利用できるのは便利ですね^^

バグ

Re:ゲーム

#26

投稿記事 by バグ » 18年前

実は、私も霧子さんのソースをとりあえず動くようにしてみたのですが、どうにもおかしな動きをしていたので、解析してみると…前記のような理由だったんです(^_^;)

霧子

Re:ゲーム

#27

投稿記事 by 霧子 » 18年前

バグさん、管理人さんいろいろと補足説明ありがとうございます。

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

フリオ

Re:ゲーム

#28

投稿記事 by フリオ » 18年前

 
>変数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:ゲーム

#29

投稿記事 by 管理人 » 18年前

う~ん、ライフゲーム自体はじめてみたもので^^;

霧子

Re:ゲーム

#30

投稿記事 by 霧子 » 18年前

フリオさんご指摘ありがとうございます。

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

閉鎖

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