ファイルの分割がうまくいかない

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

ファイルの分割がうまくいかない

#1

投稿記事 by tonari » 2年前

以前からオセロの質問をしていたものです
今度はシーンごとに分けてプログラムを書きたいのですが、
SceneManager.cpp内のChangeScene()の中で
Me_PutPice(board_y, board_x, turn);とAI_PutPice(board_y, board_x, turn);
の扱いに困っています。
外部ファイルのグロ-バル変数を参照するためにextern宣言をしているのですがこの変数の定義が
Game.cpp内の初期化関数にあるのでうまくいってないのだと思っています。
今行いたい処理は、前回質問した通りのプログラムが動いてくれればいいのですが、このシーンを管理する処理でつまずいています。
そもそもファイルの分け方がこれでいいのかすらわかっていません・・・
わかりにくい質問になってしまったのでわかりずらいところは指摘を入れてもらいながらの
返信をお待ちしております。
前回の質問
http://dixq.net/forum/viewtopic.php?f=3&t=19439
※なぜかファイルの添付がうまくいかなかったのでベタ打ちです、すみません。
※main関数には Init_First(),メインループにはChangeScene()のみです
※ヘッダーファイルには関数のプロトタイプ宣言のみしてあります
※コンパイラーはvisualstudio2017,です。

コード:

//Game.cpp
#include "DxLib.h"
#include "Input.h"
#include "Game.h"

//確定的な値
const int SCREEN_WIDIH = 840;
const int SCREEN_HEIGHT = 640;
const int vec_y[] = { -1,-1,0,1,1,1,0,-1 };
const int vec_x[] = { 0,1,1,1,0,-1,-1,-1 };

//途中で変更する可能性のある値
extern enum GameData
{
	Me = 0,			  //自分のターン
	You = 1,		  //相手のターン
	End = 2,		  //終了
	EMPTY = 0,		  //空きマス
	BLACK = 1,		  //黒コマ
	WHITE = 2,		  //白コマ
	BOARDSIZE = 8,	  //ボードの大きさ,8 * 8
	CELLSIZE = 80,	  //マス一つ分の大きさ
	CURSOR_MAX = 480  //カーソルの移動できる最大値
};
//ゲーム情報
struct Obj
{
	int Handle,		//画像データ格納用
		x,			//カーソル用
		y,
		num;		//コマを数を格納
};
Obj BoardGraph;
Obj Black;
Obj White;
Obj cursor;
int  board_x;
int  board_y;
int  turn;
int Board[BOARDSIZE][BOARDSIZE];
//画像の初期化
void Init_Graph()
{
	BoardGraph.Handle = LoadGraph("Graph/ボード.bmp");
	cursor.Handle = LoadGraph("Graph/カーソル.png");
	Black.Handle = LoadGraph("Graph/黒.png");
	White.Handle = LoadGraph("Graph/白.png");
}
//ゲーム情報の初期化
void Init_Game()
{
	turn = Me;	//ターン、0は黒が先手
	board_x = BOARDSIZE,
	board_y = BOARDSIZE;
	Black.num = 0;
	White.num = 0;
	cursor.x = 0;
	cursor.y = 0;
}
//ボードの初期化
void Init_Board()
{

	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			Board[y][x] = EMPTY;
		}
	}
	Board[BOARDSIZE / 2 - 1][BOARDSIZE / 2] = BLACK;		//[3][4]
	Board[BOARDSIZE / 2][BOARDSIZE / 2 - 1] = BLACK;		//[4][3]
	Board[BOARDSIZE / 2][BOARDSIZE / 2] = WHITE;			//[4][4]
	Board[BOARDSIZE / 2 - 1][BOARDSIZE / 2 - 1] = WHITE;	//[3][3]
}
//カーソルの移動
void Updata_cursor()
{
	if (Key(KEY_INPUT_RIGHT) == 1 && cursor.x <= CURSOR_MAX)
	{
		cursor.x += CELLSIZE;
	}
	if (Key(KEY_INPUT_LEFT) == 1 && cursor.x > 0)
	{
		cursor.x -= CELLSIZE;
	}
	if (Key(KEY_INPUT_UP) == 1 && cursor.y > 0)
	{
		cursor.y -= CELLSIZE;
	}
	if (Key(KEY_INPUT_DOWN) == 1 && cursor.y <= CURSOR_MAX)
	{
		cursor.y += CELLSIZE;
	}
}
//vecで指定された向きについてひっくり返るコマがあるか確認する(8方向のチェック)
int CheckFlip(int y, int x, int turn, int vec)	//確認出来たらTRUEを返す(ひっくり返せるコマがある)
{
	int flag = FALSE;
	while (TRUE)
	{
		//8方向の走査
		y += vec_y[vec];
		x += vec_x[vec];

		//盤面の外に出ていたら終了
		if (x < 0 || y < 0 || x > BOARDSIZE - 1 || y > BOARDSIZE - 1)
		{
			return FALSE;
		}
		//空きマスだったら終了
		if (Board[y][x] == EMPTY)
		{
			return FALSE;
		}
		//相手のコマがあったらフラグを立てる
		if (Board[y][x] == (turn ? BLACK : WHITE))
		{
			flag = TRUE;
		}
		//自分のコマがあった場合にフラグが立っていれば置ける
		if (Board[y][x] == (turn ? WHITE : BLACK))
		{
			if (flag == TRUE)
			{
				return TRUE;
			}
			//置けない
			else
			{
				return FALSE;
			}
		}
	}
	return TRUE;
}
//その場所に置くことができるかを確認
int PutCheck(int y, int x, int turn)	//置ければTRUEを返す
{
	int vec;
	//どれか1方向でもひっくり返せるか確認
	for (vec = 0; vec < 8; ++vec)
	{
		if (CheckFlip(y, x, turn, vec) == TRUE)
		{
			return TRUE;	//ひっくり返せる
		}
	}
	return FALSE;
}
//実際に裏返す処理
void Flip(int y, int x, int turn, int vec)
{
	while (1)
	{
		y += vec_y[vec];
		x += vec_x[vec];

		//自分のコマがあったら終了	
		if (Board[y][x] == (turn ? WHITE : BLACK))
		{
			break;
		}
		//それ以外なら自分のコマで塗りつぶす
		Board[y][x] = (turn ? WHITE : BLACK);
	}
}
//入力を受けて裏返せるか確かめる関数
int Put(int y, int x, int turn)
{
	int vec,
		flag = FALSE;
	//空きマスでなければ終了
	if (Board[y][x] != EMPTY)
	{
		return FALSE;
	}
	//全方向について確認
	for (vec = 0; vec < BOARDSIZE; ++vec)
	{
		if (CheckFlip(y, x, turn, vec) == TRUE)
		{
			//裏返す
			Flip(y, x, turn, vec);
			flag = TRUE;
		}
	}
	if (flag == TRUE)
	{
		//この場所にコマを置く
		Board[y][x] = (turn ? WHITE : BLACK);
		return TRUE;
	}
	return FALSE;
}
//終了判定(ターンチェンジ)
int CheckEnd(int turn)
{
	//置ける場所があるか確認
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			//あれば続行しターンチェンジ
			if (Board[y][x] == EMPTY && PutCheck(y, x, turn) == TRUE)
			{
				return (turn == Me ? Me : You);
			}
		}
	}
	//場所がなかったので交替して探す
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			//あればpassして続行
			if (Board[y][x] == EMPTY && PutCheck(y, x, turn) == TRUE)
			{
				return (turn == Me ? Me : You);
			}
		}
	}
	//なかったのでゲーム終了
	return End;
}
//コマを置く処理
void Me_PutPice(int by, int bx, int &turn)
{
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			if (Key(KEY_INPUT_Z) == 1 && CELLSIZE * x == cursor.x && CELLSIZE * y == cursor.y && turn == Me)
			{
				if (Put(y, x, turn) == 1)
				{
					Board[by][bx] = BLACK;
					turn = You;
				}
			}
		}
	}
}
//CPU,置ける所に適当に置く
void AI_PutPice(int by, int bx, int &turn)
{
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			if (Key(KEY_INPUT_X) == 1 && turn == You)
			{
				if (Put(y, x, turn) == 1)
				{
					Board[by][bx] = WHITE;
					turn = Me;
				}
			}
		}
	}
}
//勝敗判定とその時の表示
void CheckWinner()
{
	//コマを数え上げる
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			switch (Board[y][x])
			{
			case BLACK:
				++Black.num;
				break;
			case WHITE:
				++White.num;
				break;
			}
		}
	}
	if (Black.num > White.num)
	{
		DrawFormatString(680, 100, GetColor(255, 255, 255), "黒の勝ちです");
	}
	else if (Black.num < White.num)
	{
		DrawFormatString(680, 100, GetColor(255, 255, 255), "白の勝ちです");
	}
	else
	{
		DrawFormatString(680, 100, GetColor(255, 255, 255), "引き分けです");
	}
}
//ゲーム情報の表示
void Draw_Game()
{
	//盤面
	DrawGraph(0, 0, BoardGraph.Handle, false);
	//文字
	if (turn == Me)
	{
		DrawFormatString(680, 50, GetColor(255, 255, 255), "黒のターン");
	}
	if (turn == You)
	{
		DrawFormatString(680, 50, GetColor(255, 255, 255), "黒のターン");
		DrawFormatString(680, 70, GetColor(255, 255, 255), "Xキーで置きます");
	}
	//コマ
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			//ボードの情報がWHITEなら白コマが置かれる
			if (Board[y][x] == WHITE)
			{
				DrawGraph(CELLSIZE * x, CELLSIZE * y, White.Handle, true);
			}
			//ボードの情報がBLACKなら黒コマが置かれる
			if (Board[y][x] == BLACK)
			{
				DrawGraph(CELLSIZE * x, CELLSIZE * y, Black.Handle, true);
			}
		}
	}
	//グリッド線を引く
	for (int x = 0; x < 9; ++x)
	{
		//縦線
		DrawLineAA((float)CELLSIZE * x, 0.f, (float)CELLSIZE * x, (float)SCREEN_HEIGHT, GetColor(0, 0, 0), 1.4f);
	}
	for (int y = 0; y < 9; ++y)
	{
		//横線
		DrawLineAA(0.f, (float)CELLSIZE * y, (float)SCREEN_HEIGHT, (float)CELLSIZE * y, GetColor(0 ,0 ,0), 1.4f);
	}
	//カーソルの表示
	DrawGraph(cursor.x, cursor.y, cursor.Handle, true);
}
シーンの管理

コード:

//SceneManager.cpp内
#include "DxLib.h"
#include "Input.h"
#include "Game.h"
#include "SceneManager.h"

 enum GameData
{
	End = 2,		  //終了
};

enum Scene
{
	//あとから追加
	Game,

};Scene scene;
extern int board_y;
extern int board_x;
extern int turn;
//初回起動時のみ実行
void Init_First()
{
	Init_Graph();
	Init_Board();
	Init_Game();
}
//シーン管理
void ChangeScene()
{
	switch (scene)
	{
	case Game:
		Updata_Key();			//キー入力を有効にする
		Updata_cursor();
		Me_PutPice(board_y, board_x, turn);
		AI_PutPice(board_y, board_x, turn);
		turn = CheckEnd(turn);
		switch (turn)
		{
		case End:
			CheckWinner();
			break;
		}
		Draw_Game();
		break;
	}
}

最後に編集したユーザー tonari on 2017年8月02日(水) 19:46 [ 編集 7 回目 ]

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

Re: ファイルの分割がうまくいかない

#2

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

本当にわかりにくい質問ですね。
「この変数の定義がGame.cpp内の初期化関数にある」ってどういうことですか?ローカル変数(なのかもわかりませんが)はextern宣言しても外部ファイルからは参照できないでしょう。
「前回質問した通りのプログラム」って何ですか?リンクかプログラムがあるとわかりやすいかもしれません。
「このシーンを管理する処理」って何ですか?
「ファイルの分け方がこれでいいのかすらわかっていません」の「これ」って何ですか?

【追記】
入れ違いでコードが投稿されたようですね。これから読もうと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: ファイルの分割がうまくいかない

#3

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

とりあえずコンパイルを試みたところ、

コード:

Game.cpp:24:1: error: a storage class can only be specified for objects and functions
 };
 ^
というエラーが出ました。
enumは変数や関数の宣言や定義ではなく型の宣言なので、externは不要(むしろ蛇足)ですね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

tonari
記事: 28
登録日時: 2年前

Re: ファイルの分割がうまくいかない

#4

投稿記事 by tonari » 2年前

返信ありがとうございます
enumのexternを直しました。
extrenを使うと外部ファイルからでもプロトタイプ宣言した関数や
グローバル変数を参照できるという認識であっているのでしょうか?

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

Re: ファイルの分割がうまくいかない

#5

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

Game.cpp 13行目のexternを削除し、以下のファイルを加えた所、コンパイルは通りました。
► スポイラーを表示
tonari さんが書きました:extrenを使うと外部ファイルからでもプロトタイプ宣言した関数や
グローバル変数を参照できるという認識であっているのでしょうか?
プロトタイプ宣言した関数やグローバル関数であっても、staticを用いて定義したものはexternを使っても参照できないでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
keito94
記事: 264
登録日時: 2年前
連絡を取る:

Re: ファイルの分割がうまくいかない

#6

投稿記事 by keito94 » 2年前

オフトピック
externって、C++では使う機会あまりないからね…。
仕方ないね。
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

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

Re: ファイルの分割がうまくいかない

#7

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

tonari さんが書きました: SceneManager.cpp内のChangeScene()の中で
Me_PutPice(board_y, board_x, turn);とAI_PutPice(board_y, board_x, turn);
の扱いに困っています。
どう困っているのかがよくわかりませんが、Game.cppに「オセロを1フレームやる」関数を作って、
今ChangeScene()のcase Game:でやっている処理をその関数に移した方がいいと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

tonari
記事: 28
登録日時: 2年前

Re: ファイルの分割がうまくいかない

#8

投稿記事 by tonari » 2年前

返信ありがとうございます。
自分のやりたいことをまとめるとSceneManager.cppですべてのシーン(タイトルなど)とゲームの処理をまとめて、
メインループには、ChangeScene()と、シャットダウンする処理のみを書くつもりで設計しています。
なので、ChangeScene()内の引数のある関数をそのファイル内でも使えるようにしたいのです。
そもそもそれは可能なのでしょうか?見当違いでしたらすみません。自分の勉強不足です。
もっと言うと以下のソースコードの内容を分割コンパイルし、またあとからシーンを切り替えたり、
機能の追加をしやすくするために、SceneManager.cppを作りました。

コード:

 
//ゲーム部分のみ完成したオセロプログラム
//多少の違いはありますが、今質問に乗せている内容とほぼ同じです
#include "DxLib.h"

int key[256];

int gpUpdatekey()
{
	char tmpkey[256];				//現在のキーの入力状態を格納
	GetHitKeyStateAll(tmpkey);		//すべてのキーの入力状態を得る
	for (int i = 0; i < 256; ++i)
	{
		if (tmpkey[i] != 0)
		{
			++key[i];
		}
		else
		{
			key[i] = 0;
		}
	}
	return 0;
}
struct Obj {
	int x,
		y,
		w,
		h,
		Handle;
};
enum Game_Data {
	Me = 0,
	CPU = 1,
	End = 2,
	EMPTY = 0,
	BLACK = 1,
    WHITE = 2,
	SCREEN_WIDIH = 840,
	SCREEN_HEIGHT = 640,
	CURSOR_MAX = 480,
	CELLSIZE = 80,
	BOARDSIZE = 8

};

int board_x,
	board_y;
int b,	//ゲーム終了時にコマの数を数えるための変数
	w;
int board[BOARDSIZE][BOARDSIZE];
int boardGraph;
int vec_y[] = { -1,-1,0,1,1,1,0,-1 };
int vec_x[] = { 0,1,1,1,0,-1,-1,-1 };
Obj black;
Obj white;
Obj cursor;
int turn;
//画像のロード
void Graph_Ini()
{
	 boardGraph   = LoadGraph("画像/オセロ.bmp");
	 black.Handle = LoadGraph("画像/クロ駒.bmp");
	 white.Handle = LoadGraph("画像/シロ駒.bmp");
	 cursor.Handle = LoadGraph("画像/選択.png");
}
//ゲーム情報の初期化
void Game_Ini()
{
	turn = Me;	//ターン、0は黒が先手
	board_x = BOARDSIZE,
	board_y = BOARDSIZE;
}
//盤面の初期化
void Board_Ini()
{
	
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			board[y][x] = EMPTY;
		}
	}
	board[BOARDSIZE / 2 - 1][BOARDSIZE / 2]		= BLACK;	//[3][4]
	board[BOARDSIZE / 2][BOARDSIZE / 2 - 1]		= BLACK;	//[4][3]
	board[BOARDSIZE / 2][BOARDSIZE / 2]  		= WHITE;	//[4][4]
	board[BOARDSIZE / 2 - 1][BOARDSIZE / 2 - 1] = WHITE;	//[3][3]
}
//カーソルの初期化
void Cursor_Ini()
{
	cursor.x = 0;
	cursor.y = 0;
}
//カーソルの移動
void Cursor_Move()
{
	if (key[KEY_INPUT_RIGHT] == 1 && cursor.x <= CURSOR_MAX)
	{
		cursor.x += CELLSIZE;
	}
	if (key[KEY_INPUT_LEFT] == 1 && cursor.x > 0)
	{
		cursor.x -= CELLSIZE;
	}
	if (key[KEY_INPUT_UP] == 1 && cursor.y > 0)
	{
		cursor.y -= CELLSIZE;
	}
	if (key[KEY_INPUT_DOWN] == 1 && cursor.y <= CURSOR_MAX)
	{
		cursor.y += CELLSIZE;
	}
}
//vecで指定された向きについてひっくり返るコマがあるか確認する(8方向のチェック)
int CheckFlip(int y, int x, int turn, int vec)
{
	int flag = 0;
	while (1)
	{
		y += vec_y[vec];
		x += vec_x[vec];

		//盤面の外に出ていたら終了(盤面内か?)
		if (x < 0 || y < 0 || x > BOARDSIZE - 1 || y > BOARDSIZE - 1)
		{
			return 0;
		}
		//空きマス(置けるマス)だったら終了(その場所はおけるか?)
		if (board[y][x] == EMPTY)
		{
			return 0;
		}
		//相手のコマがあったらフラグを立てる
		if (board[y][x] == (turn ? BLACK : WHITE))	//真なら黒(1)、偽なら白(0)
		{
			flag = 1;
			
		}
		//自分のコマがあった場合にフラグが立っていれば置ける
		if (board[y][x] == (turn ? WHITE : BLACK))
		{
			if (flag == 1)
			{
				return 1;
			}
			//置けない
			else
			{
				return 0;
			}
		}
	}
	return 1;
}
//その場所に置くことができるかを確認
int Check(int y, int x, int turn)	//座標とターン
{
	int vec;
	//どれか一方向でもひっくり返るか確認
	for (vec = 0; vec < 8; ++vec)
	{
		if (CheckFlip(y, x, turn, vec) == 1)
		{
			return 1;	//ひっくり返るなら1を返す
		}
	}
	return 0;			//0は返せない
}
//実際に裏返す処理
void Flip(int y, int x, int turn, int vec)
{
	while (1)
	{
		y += vec_y[vec];
		x += vec_x[vec];

		//自分のコマがあったら終了
		if (board[y][x] == (turn ? WHITE : BLACK))
		{
			break;
		}
		//それ以外なら自分の駒で塗りつぶす
		board[y][x] = (turn ? WHITE : BLACK);
	}
}
//入力を受けて裏返せるか確かめる関数
int Put(int y, int x, int turn)
{
	int vec,
		flag = 0;
	//空白でなければ終了
	if (board[y][x] != EMPTY)
	{
		return 0;
	}
	//全方向について確認
	for (vec = 0; vec < 8; ++vec)
	{
		if (CheckFlip(y, x, turn, vec) == 1)
		{
			//裏返す
			Flip(y, x, turn, vec);
			flag = 1;
		}
	}
	if (flag == 1)
	{
		//この場所にコマを置く
		board[y][x] = (turn ? WHITE : BLACK);
		return 1;
	}
	return 0;
}
//終了判定
int CheckEnd(int turn)
{
	int y,
		x;
	//おける場所があるか確認
	for (y = 0; y < BOARDSIZE; ++y)
	{
		for (x = 0; x < BOARDSIZE; ++x)
		{
			//あれば普通に続行
			if (board[y][x] == EMPTY && Check(y, x, turn) == 1)
			{
				return (turn == Me ? Me : CPU);
			}
		}
	}
	//場所がなかったので交替して探す
	for (y = 0; y < BOARDSIZE; ++y)
	{
		for (x = 0; x < BOARDSIZE; ++x)
		{
			//あればpassして続行
			if (board[y][x] == EMPTY && Check(y, x, turn) == 1)
			{
				return (turn == Me ? Me : CPU);
			}
		}
	}
	//なかったのでゲーム終了
	return End;
}
//コマを置く処理
void Me_PutPice(int by, int bx, int &turn)
{
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			if (key[KEY_INPUT_Z] == 1 && CELLSIZE * x == cursor.x && CELLSIZE * y == cursor.y && turn == Me)
			{
				if (Put(y, x, turn) == 1)
				{
					board[by][bx] = BLACK;
					turn = CPU;
				}
			}
		}
	}
}
//CPU置ける所に適当に置く
void AI(int by, int bx, int &turn)
{
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			if (key[KEY_INPUT_X] == 1 && turn == CPU)
			{
				if (Put(y, x, turn) == 1)
				{
					board[by][bx] = WHITE;
					turn = Me;
				}
			}
		}
	}
}
//勝敗判定
void CheckWinner()
{
	b = 0,
	w = 0;
	//コマを数え上げる
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			switch (board[y][x])
			{
			case BLACK:
				++b;
				break;
			case WHITE:
				++w;
				break;
			default:
				break;
			}
		}
	}
	//勝敗決定時
	if (b > w)
	{
		DrawFormatString(680, 100, GetColor(255, 255, 255), "黒の勝ちです");
	}
	else if (b < w)
	{
		DrawFormatString(680, 100, GetColor(255, 255, 255), "白の勝ちです");
	}
	else
	{
		DrawFormatString(680, 100, GetColor(255, 255, 255), "引き分けです");
	}
}
//盤面の表示
void Draw_Board()
{
	//盤面
	DrawGraph(0, 0, boardGraph, false);
	//文字の表示
	if (turn == Me)
	{
		DrawFormatString(680, 50, GetColor(255, 255, 255), "黒(自分)のターン");
	}
	if (turn == CPU)
	{
		DrawFormatString(680, 50, GetColor(255, 255, 255), "白(CPU)のターン");
		DrawFormatString(680, 70, GetColor(255, 255, 255), "Xキーで置きます");
	}
	//コマ
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
				//ボードの情報がWHITEなら白コマが置かれる
				if (board[y][x] == WHITE)
				{
					DrawGraph(CELLSIZE * x, CELLSIZE * y, white.Handle, false);
				}
				//ボードの情報がBLACKなら黒コマが置かれる
				if (board[y][x] == BLACK)
				{
					DrawGraph(CELLSIZE * x, CELLSIZE * y, black.Handle, false);
				}
		}
	}
	//グリッド線を引く
	for (int x = 0; x < 9; ++x)
	{
		DrawLine(CELLSIZE * x, 0, CELLSIZE * x, SCREEN_HEIGHT, GetColor(255, 255, 255), true);
	}
	for (int y = 0; y < 9; ++y)
	{
		DrawLine(0, CELLSIZE * y, SCREEN_HEIGHT, CELLSIZE * y, GetColor(255, 255, 255), true);
	}
	//カーソル
	DrawGraph(cursor.x, cursor.y, cursor.Handle,true);
}
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);	//ウィンドウモード変更と初期化と裏画面設定
	SetGraphMode(SCREEN_WIDIH, SCREEN_HEIGHT, 32);

	Graph_Ini();
	Game_Ini();
	Cursor_Ini();
	Board_Ini();

	// while(裏画面を表画面に反映、メッセージ処理、画面クリア、キーの更新)
	while(ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdatekey() == 0)						//無限ループ
	{
		//ここにゲームの処理を描く------------------------------------------------
			Cursor_Move();
			Me_PutPice(board_y, board_x, turn);
			AI(board_y, board_x, turn);
			turn = CheckEnd(turn);
			switch(turn)
			{
			case End:
				CheckWinner();
				break;
			}
		Draw_Board();
		//----------------------------------------------------------------------
	}
        DxLib_End();							// DXライブラリ終了処理
        return 0;
}
 

tonari
記事: 28
登録日時: 2年前

Re: ファイルの分割がうまくいかない

#9

投稿記事 by tonari » 2年前

大変申し訳ありません
Put関数内の処理に致命的なミスがあったので直しておきます
変更前
for(vec=0;vec<0;++vec)
変更後
for(vec=0;vec<BOARDSIZE;++vec)
です。

tonari
記事: 28
登録日時: 2年前

Re: ファイルの分割がうまくいかない

#10

投稿記事 by tonari » 2年前

みけcatさんの通り1フレームだけオセロをする処理を書いたところうまくいきました。
以下がソースコードです

コード:

//Game.cpp
#include "DxLib.h"
#include "Input.h"
#include "Game.h"
#include "SceneManager.h"

//確定的な値
static const int 
SCREEN_WIDIH = 840,				 
SCREEN_HEIGHT = 640,	
//8方向の判定用
vec_y[] = { -1,-1,0,1,1,1,0,-1 },
vec_x[] = { 0,1,1,1,0,-1,-1,-1 };

//途中で変更する可能性のある値
enum GameData
{
	Me = 0,			  //自分のターン
	You = 1,		  //相手のターン
	End = 2,		  //終了
	EMPTY = 0,		  //空きマス
	BLACK = 1,		  //黒コマ
	WHITE = 2,		  //白コマ
	BOARDSIZE = 8,	  //ボードの大きさ,8 * 8
	CELLSIZE = 80,	  //マス一つ分の大きさ
	CURSOR_MAX = 480  //カーソルの移動できる最大値
};
//ゲーム情報
struct Obj
{
	int Handle,		//画像データ格納用
		x,			//カーソル用
		y,
		num;		//コマを数を格納
};
Obj BoardGraph;
Obj Black;
Obj White;
Obj cursor;
int board_x;
int board_y;
int turn;
bool Gameflag;		//更新処理内で1フレームだけ処理を行う場合に使う
int Board[BOARDSIZE][BOARDSIZE];
//画像の初期化
void Init_Graph()
{
	BoardGraph.Handle = LoadGraph("Graph/ボード.bmp");
	cursor.Handle = LoadGraph("Graph/カーソル.png");
	Black.Handle = LoadGraph("Graph/黒.png");
	White.Handle = LoadGraph("Graph/白.png");
}
//ゲーム情報の初期化
void Init_Game()
{
	turn = Me;	//ターン、0は黒が先手
	Gameflag = false;
	board_x = BOARDSIZE,
	board_y = BOARDSIZE;
	Black.num = 0;
	White.num = 0;
	cursor.x = 0;
	cursor.y = 0;
}
//ボードの初期化
void Init_Board()
{

	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			Board[y][x] = EMPTY;
		}
	}
	Board[BOARDSIZE / 2 - 1][BOARDSIZE / 2] = BLACK;		//[3][4]
	Board[BOARDSIZE / 2][BOARDSIZE / 2 - 1] = BLACK;		//[4][3]
	Board[BOARDSIZE / 2][BOARDSIZE / 2] = WHITE;			//[4][4]
	Board[BOARDSIZE / 2 - 1][BOARDSIZE / 2 - 1] = WHITE;	//[3][3]
}
//カーソルの移動
void Updata_cursor()
{
	if (Key(KEY_INPUT_RIGHT) == 1 && cursor.x <= CURSOR_MAX)
	{
		cursor.x += CELLSIZE;
	}
	if (Key(KEY_INPUT_LEFT) == 1 && cursor.x > 0)
	{
		cursor.x -= CELLSIZE;
	}
	if (Key(KEY_INPUT_UP) == 1 && cursor.y > 0)
	{
		cursor.y -= CELLSIZE;
	}
	if (Key(KEY_INPUT_DOWN) == 1 && cursor.y <= CURSOR_MAX)
	{
		cursor.y += CELLSIZE;
	}
}
//vecで指定された向きについてひっくり返るコマがあるか確認する(8方向のチェック)
int CheckFlip(int y, int x, int turn, int vec)	//確認出来たらTRUEを返す(ひっくり返せるコマがある)
{
	int flag = FALSE;
	while (TRUE)
	{
		//8方向の走査
		y += vec_y[vec];
		x += vec_x[vec];

		//盤面の外に出ていたら終了
		if (x < 0 || y < 0 || x > BOARDSIZE - 1 || y > BOARDSIZE - 1)
		{
			return FALSE;
		}
		//空きマスだったら終了
		if (Board[y][x] == EMPTY)
		{
			return FALSE;
		}
		//相手のコマがあったらフラグを立てる
		if (Board[y][x] == (turn ? BLACK : WHITE))
		{
			flag = TRUE;
		}
		//自分のコマがあった場合にフラグが立っていれば置ける
		if (Board[y][x] == (turn ? WHITE : BLACK))
		{
			if (flag == TRUE)
			{
				return TRUE;
			}
			//置けない
			else
			{
				return FALSE;
			}
		}
	}
	return TRUE;
}
//その場所に置くことができるかを確認
int PutCheck(int y, int x, int turn)	//置ければTRUEを返す
{
	int vec;
	//どれか1方向でもひっくり返せるか確認
	for (vec = 0; vec < BOARDSIZE; ++vec)
	{
		if (CheckFlip(y, x, turn, vec) == 1)
		{
			return TRUE;	//ひっくり返せる
		}
	}
	return FALSE;
}
//実際に裏返す処理
void Flip(int y, int x, int turn, int vec)
{
	while (TRUE)
	{
		y += vec_y[vec];
		x += vec_x[vec];

		//自分のコマがあったら終了	
		if (Board[y][x] == (turn ? WHITE : BLACK))
		{
			break;
		}
		//それ以外なら自分のコマで塗りつぶす
		Board[y][x] = (turn ? WHITE : BLACK);
	}
}
//入力を受けて裏返せるか確かめる関数
int Put(int y, int x, int turn)
{
	int vec,
		flag = FALSE;
	//空きマスでなければ終了
	if (Board[y][x] != EMPTY)
	{
		return FALSE;
	}
	//全方向について確認
	for (vec = 0; vec < BOARDSIZE; ++vec)
	{
		if (CheckFlip(y, x, turn, vec) == 1)
		{
			//裏返す
			Flip(y, x, turn, vec);
			flag = TRUE;
		}
	}
	if (flag == TRUE)
	{
		//この場所にコマを置く
		Board[y][x] = (turn ? WHITE : BLACK);
		return TRUE;
	}
	return FALSE;
}
//終了判定(ターンチェンジ)
int CheckEnd(int turn)
{
	//置ける場所があるか確認
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			//あれば続行しターンチェンジ
			if (Board[y][x] == EMPTY && PutCheck(y, x, turn) == TRUE)
			{
				return (turn == Me ? Me : You);
			}
		}
	}
	//場所がなかったので交替して探す
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			//あればpassして続行
			if (Board[y][x] == EMPTY && PutCheck(y, x, turn) == TRUE)
			{
				return (turn == Me ? Me : You);
			}
			
		}
	}
	return End;
}
//コマを置く処理
void Me_PutPice(int by, int bx, int &turn)
{
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			if (Key(KEY_INPUT_Z) == 1 && CELLSIZE * x == cursor.x && CELLSIZE * y == cursor.y && turn == Me)
			{
				if (Put(y, x, turn) == TRUE)
				{
					Board[by][bx] = BLACK;
					turn = You;
				}
			}
		}
	}
}
//CPU,置ける所に適当に置く
void AI_PutPice(int by, int bx, int &turn)
{
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			if  (turn == You)
			{
				if (Put(y, x, turn) == TRUE)
				{
					Board[by][bx] = WHITE;
					turn = Me;
				}
			}
		}
	}
}
//対人
void You_PutPice(int by, int bx, int &turn)
{
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			if (Key(KEY_INPUT_Z) == 1 && CELLSIZE * x == cursor.x && CELLSIZE * y == cursor.y && turn == You)
			{
				if (Put(y, x, turn) == TRUE)
				{
					Board[by][bx] = WHITE;
					turn = Me;
				}
			}
		}
	}
}
//コマを数える
void CountPice()
{
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			switch (Board[y][x])
			{
			case BLACK:
				++Black.num;
				break;
			case WHITE:
				++White.num;
				break;
			default:
				break;
			}
		}
	}
}
//ゲーム情報の表示
void Draw_Game()
{
	//盤面
	DrawGraph(0, 0, BoardGraph.Handle, false);
	//文字
	if (turn == Me)
	{
		DrawFormatString(680, 50, GetColor(255, 255, 255), "黒(自分)のターン");
	}
	if (turn == You)
	{
		DrawFormatString(680, 50, GetColor(255, 255, 255), "白(相手)のターン");
	}
	if (turn == End)
	{
		DrawFormatString(680, 300, GetColor(255, 255, 255), "Rでリトライ");
		DrawFormatString(680, 320, GetColor(255, 255, 255), "Fでシャットダウン");
		if (Black.num > White.num)
		{
			DrawFormatString(680, 100, GetColor(255, 255, 255), "黒の勝ちです");
		}
		else if (Black.num < White.num)
		{
			DrawFormatString(680, 100, GetColor(255, 255, 255), "白の勝ちです");
		}
		else
		{
			DrawFormatString(680, 100, GetColor(255, 255, 255), "引き分けです");
		}
	}
	//コマ
	for (int y = 0; y < BOARDSIZE; ++y)
	{
		for (int x = 0; x < BOARDSIZE; ++x)
		{
			//ボードの情報がWHITEなら白コマが置かれる
			if (Board[y][x] == WHITE)
			{
				DrawGraph(CELLSIZE * x, CELLSIZE * y, White.Handle, true);
			}
			//ボードの情報がBLACKなら黒コマが置かれる
			if (Board[y][x] == BLACK)
			{
				DrawGraph(CELLSIZE * x, CELLSIZE * y, Black.Handle, true);
			}
		}
	}
	//グリッド線を引く
	for (int x = 0; x < 9; ++x)
	{
		//縦線
		DrawLineAA((float)CELLSIZE * x, 0.f, (float)CELLSIZE * x, (float)SCREEN_HEIGHT, GetColor(0, 0, 0), 1.4f);
	}
	for (int y = 0; y < 9; ++y)
	{
		//横線
		DrawLineAA(0.f, (float)CELLSIZE * y, (float)SCREEN_HEIGHT, (float)CELLSIZE * y, GetColor(0 ,0 ,0), 1.4f);
	}
	//カーソルの表示
	DrawGraph(cursor.x, cursor.y, cursor.Handle, true);
}
//以下は上記の処理をまとめたもの-------------------------------------------------------------------------------
//毎フレームごとに処理を行う
int Main_Program(int &turn)		//対CPU
{
	while(Gameflag == false)
	{
		Updata_cursor();
		Me_PutPice(board_y, board_x, turn);
		AI_PutPice(board_y, board_x, turn);
		turn = CheckEnd(turn);				//CheckEndの戻り値をturnに入れる(ターンの切り替え)
		Gameflag = true;					//処理を行ったたらすぐにtrueにする(これで1フレームだけ処理を行う)
		if (Gameflag == true)
		{
			break;
		}	
	}
	CountPice();
	Draw_Game();
	Gameflag = false;
	return turn;
}
int Main_Program2(int &turn)	//対人間
{
	while (Gameflag == false)
	{
		Updata_cursor();
		Me_PutPice(board_y, board_x, turn);
		You_PutPice(board_y, board_x, turn);
		turn = CheckEnd(turn);				//CheckEndの戻り値をturnに入れる(ターンの切り替え)
		Gameflag = true;					//処理を行ったたらすぐにtrueにする(これで1フレームだけ処理を行う)
		if (Gameflag == true)
		{
			break;
		}
	}
	CountPice();
	Draw_Game();
	Gameflag = false;
	return turn;
}
//------------------------------------------------------------------------------------------------------------

コード:

 
//SceneManager.cpp
#include "DxLib.h"
#include "Input.h"
#include "Game.h"
#include "SceneManager.h"
#include "Title.h"

 enum GameData
{
	End = 2,		  //終了
};

enum Scene
{
	//必要に応じて追加
	Title,
	Game_cpu,
	Game_human

};Scene scene;

extern int turn;

//タイトルシーンの初期化
void Init_Title()
{
	TitleGraph_Init();
}
//ゲーム本編の初期化
void Init_MainGame()
{
	Init_Graph();
	Init_Board();
	Init_Game();
}
//シーン管理
void ChangeScene()
{
	switch (scene)
	{
	case Title:
		Draw_Title();
		if (Key(KEY_INPUT_S) == 1)
		{
			//ゲームの初期化
			Init_MainGame();
			//シーンをゲーム本編(CPU)へ
			scene = Game_cpu;
		}
		if (Key(KEY_INPUT_W) == 1)
		{
			//ゲームの初期化
			Init_MainGame();
			//シーンをゲーム本編(対人)へ
			scene = Game_human;
		}
		break;
	case Game_cpu:
		//毎フレーム処理をする
		Main_Program(turn);		//対CPU
		//リトライ
		if (turn == End && Key(KEY_INPUT_R) == 1)
		{
			//ゲームの初期化
			Init_MainGame();
		}
		//シャットダウン
		if (turn == End && Key(KEY_INPUT_F) == 1)
		{
			InitGraph();	//すべての画像データを削除	
			DxLib_End();	//DXライブラリ終了処理
		}
		break;
	case Game_human:
		Main_Program2(turn);	//対人間
		//リトライ
		if (turn == End && Key(KEY_INPUT_R) == 1)
		{
			//ゲームの初期化
			Init_MainGame();
		}
		//シャットダウン
		if (turn == End && Key(KEY_INPUT_F) == 1)
		{
			InitGraph();		//すべての画像データを削除	
			DxLib_End();		//DXライブラリ終了処理
		}
		break;
	}
}


いろいろ追加しているところがありますが変更点は質問していたところのみです

アバター
keito94
記事: 264
登録日時: 2年前
連絡を取る:

Re: ファイルの分割がうまくいかない

#11

投稿記事 by keito94 » 2年前

tonari さんが書きました: for(vec=0;vec<0;++vec)
こういうfor文のタイプミスは、よくありがちだと思います。
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

tonari
記事: 28
登録日時: 2年前

Re: ファイルの分割がうまくいかない

#12

投稿記事 by tonari » 2年前

散々悩んだ挙句、そういうミスをすると脱力しますよね(笑

返信

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