Project:MineSweeper

アバター
藍沢 冬月
記事: 0
登録日時: 14年前
住所: 京都
連絡を取る:

Project:MineSweeper

投稿記事 by 藍沢 冬月 » 14年前

CODE:

/*=============================================*
 *
 *   マインスイーパ―簡易版
 *   provided by C
 *
*=============================================*/

#include "DxLib.h"

// プロトタイプ宣言
int Search( int Field[ 10 ][ 10 ] , int Clicks[ 10 ][ 10 ] , int px , int py ) ;

// グローバル変数宣言
// はじめ、消さなくてはならないマスは全部で90コある
int Block_n = 90 ;

// WinMain関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
					 LPSTR lpCmdLine, int nCmdShow )
{
	char Key[ 256 ] ;

	// ウインドウモードに変更
	if( ChangeWindowMode( TRUE ) != DX_CHANGESCREEN_OK ) return -1 ;

	// 画面モードの変更
	// サイズはぎりぎりいっぱいでいいと思うよ
	if( SetGraphMode( 22 * 10 , 22 * 10 , 32 ) != DX_CHANGESCREEN_OK ) return -1 ;

	// タイトルを変更
	SetMainWindowText( "MineSweeper" ) ;

	// DXライブラリ初期化処理
	if( DxLib_Init() == -1 ) return -1;

	// この配列に地雷情報を突っ込む
	int Field[ 10 ][ 10 ] = { 0 } ;

	// この配列にはクリックしたか(値が公開されているかどうか)どうかのフラグを突っ込む
	int Clicks[ 10 ][ 10 ] = { 0 } ;

	// 地雷セット
	int mine_n = 0 ;
	while( mine_n < 10 )
	{
		int px , py ;

		// 地雷の場所がかぶらないように注意してマスを選ぶ
		do
		{
			px = GetRand( 10 - 1 ) ;
			py = GetRand( 10 - 1 ) ;
		} while( Field[ px ][ py ] == -1 ) ;

		// Fieldのどこかにランダムで地雷を埋める
		Field[ px ][ py ] = -1 ;

		// 地雷の情報からその周囲のマスに地雷情報を付け足す
		if( px != 0 )
		{
			if( Field[ px - 1 ][ py ] != -1 ) Field[ px - 1 ][ py ] ++ ;
			if( py != 0 && Field[ px - 1 ][ py - 1 ] != -1 ) Field[ px - 1 ][ py - 1 ] ++ ;
		}
		if( py != 0 )
		{
			if( Field[ px ][ py - 1 ] != -1 ) Field[ px ][ py - 1 ] ++ ;
			if( px != 10 - 1 && Field[ px + 1 ][ py - 1 ] != -1 ) Field[ px + 1 ][ py - 1 ] ++ ;
		}
		if( px != 10 - 1 )
		{
			if( Field[ px + 1 ][ py ] != -1 ) Field[ px + 1 ][ py ] ++ ;
			if( py != 10 - 1 && Field[ px + 1 ][ py + 1 ] != -1 ) Field[ px + 1 ][ py + 1 ] ++ ;
		}
		if( py != 10 - 1 )
		{
			if( Field[ px ][ py + 1 ] != -1 ) Field[ px ][ py + 1 ] ++ ;
			if( px != 0 && Field[ px - 1 ][ py + 1 ] != -1 ) Field[ px - 1 ][ py + 1 ] ++ ;
		}

		mine_n ++ ;
	}

	// マウスカーソルを見えるようにセット
	SetMouseDispFlag( TRUE );

	// マウスの位置を格納する変数
	int MouseX , MouseY ;

	// グラフィックの描画先を裏画面にセット
	SetDrawScreen( DX_SCREEN_BACK ) ;

	int g_over = 0 ;
	int g_clear = 0 ;

	// ESCキーが押されるまでループ
	while( !ProcessMessage() && !GetHitKeyStateAll( Key ) && !Key[ KEY_INPUT_ESCAPE ] )
	{
		// 画面をクリア
		ClearDrawScreen() ;

		// 描画
		for( int i = 0 ; i < 10 ; i ++ )
		{
			for( int j = 0 ; j < 10 ; j ++ )
			{
				int C_Block ;
				if( Clicks[ i ][ j ] == 0 ) C_Block = TRUE ;
				else C_Block = FALSE ;
				DrawBox( 0 + i * 22 , 0 + j * 22 , i * 22 + 20 , j * 22 + 20 , GetColor( 0 , 128 , 255 ) , C_Block ) ;

				if( Clicks[ i ][ j ] == 1 && Field[ i ][ j ] != 0 ) DrawFormatString( 8 + i * 22 , 2 + j * 22 , GetColor( 255 , 255 , 255 ) , "%d" , Field[ i ][ j ] ) ;
			}
		}

		// 全部マスを開けるとクリアー
		if( Block_n == 0 ) g_clear = 1 ;

		// マウスのクリックを検知
		if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 )
		{
			// マウスの位置を取得、フラグを立てる
			GetMousePoint( &MouseX , &MouseY ) ;

			int px = MouseX / 22 ;
			int py = MouseY / 22 ;

			// 探知開始
			Search( Field , Clicks , px , py ) ;

			// 地雷を踏んでしまったら
			if( Field[ px ][ py ] == -1 ) g_over = 1 ;
		}

		// ゲームクリアー
		if( g_clear == 1 )
			DrawString( 0 , 0 , "GAME CLEAR!" , GetColor( 255 , 0 , 0 ) ) ;

		// ゲームオーバー
		if( g_over == 1 )
			DrawString( 0 , 0 , "GAME OVER!" , GetColor( 255 , 120 , 0 ) ) ;

		// 画面を表示
		ScreenFlip() ;
	}

	// DXライブラリ使用の終了処理
	DxLib_End() ;

	// ソフトの終了
	return 0 ;
}

// マスを開ける探知再帰関数
int Search( int Field[ 10 ][ 10 ] , int Clicks[ 10 ][ 10 ] , int px , int py )
{
	if( Clicks[ px ][ py ] != 1 )
	{
		Clicks[ px ][ py ] = 1 ;
		Block_n -- ;
	}

	if( Field[ px ][ py ] == 0 )
	{
		// 左側の処理
		if( px != 0 )
		{
			if( Clicks[ px - 1 ][ py ] != 1 ) Search( Field , Clicks , px - 1 , py ) ;
			if( py != 0 && Clicks[ px - 1 ][ py - 1 ] != 1 ) Search( Field , Clicks , px - 1 , py - 1 ) ;
		}
		// 上側の処理
		if( py != 0 )
		{
			if( Clicks[ px ][ py - 1 ] != 1 ) Search( Field , Clicks , px , py - 1 ) ;
			if( px != 10 - 1 && Clicks[ px + 1 ][ py - 1 ] != 1 ) Search( Field , Clicks , px + 1 , py - 1 ) ;
		}
		// 右側の処理
		if( px != 10 - 1 )
		{
			if( Clicks[ px + 1 ][ py ] != 1 ) Search( Field , Clicks , px + 1 , py ) ;
			if( py != 10 - 1 && Clicks[ px + 1 ][ py + 1 ] != 1 ) Search( Field , Clicks , px + 1 , py + 1 ) ;
		}
		// 下側の処理
		if( py != 10 - 1 )
		{
			if( Clicks[ px ][ py + 1 ] != 1 ) Search( Field , Clicks , px , py + 1 ) ;
			if( px != 0 && Clicks[ px - 1 ][ py + 1 ] != 1 ) Search( Field , Clicks , px - 1 , py + 1 ) ;
		}
	}

	return 1 ;
}
ただ練習用に昔書いたものです。
再帰関数の練習としては便利だと思ったのでUP
ゲームオーバーまたはクリアの後にリセットでもう一度遊べるようにするべきですが、再帰の練習のためにしていません。
添付ファイル
minesweeper.jpg
minesweeper.jpg (21.28 KiB) 閲覧数: 37 回

アバター
バグ
記事: 130
登録日時: 15年前

Re: Project:MineSweeper

投稿記事 by バグ » 14年前

おっ、マインスイーパーですか。いいですね(^-^)
構造体を使うともっとスッキリするかもしれませんよ。

アバター
藍沢 冬月
記事: 0
登録日時: 14年前
住所: 京都
連絡を取る:

Re: Project:MineSweeper

投稿記事 by 藍沢 冬月 » 14年前

>>1さん
コメントありがとうございます!
構造体ですか…気がつきませんでした!
構造体ですと、↓のような感じでしょうか?

確かにすっきりするし、
旗を立てる処理を追加するとすれば、構造体でやったほうが便利だったかもしれません。

CODE:

typedef struct tagBlocks{
	// 0:なにもない
	// 1:地雷がある
	int mine_flag ;
 
	// 0:まだクリックされていない
	// 1:クリック済み
	int open_flag ;
 
	// 0:なにもない
	// 1:旗が立っている
	// 2:?マークが付いている
	int click_flag ;
} Blocks ;
 
// 構造体で宣言
Blocks blocks[ 10 ][ 10 ] ;