//個性系変数とプロパティ
public bool IsNew = true; //新規か否かのフラグ
public string Name {get; set;} //賭博者の名前(愛称) //賭博系プロパティ
public int Capital {get; set;} //掛け金の元手
public int Bet {get; private set;} //掛け金(元手×強気弱気係数)
public int Luck {get; private set;} //運、強気(bullish)弱気(bearish)の原因
public int BullBear {get; private set;} //強気弱気(掛け金の多寡に影響する) //統計系プロパティ
public int TotalGames {get; private set;} //累計勝負数
public int TotalWins {get; private set;} //累計勝ち数
public int TotalLoses {get; private set;} //累計負け数
public double TotalAverage {get; private set;} //累計勝率
public int ThisGames {get; private set;} //今回勝負数
public int ThisWins {get; private set;} //今回勝ち数
public int ThisLoses {get; private set;} //今回負け数
public double ThisAverage {get; private set;} //今回勝率
///////////////////////////////////
//TestDice.cs - テスト用プログラム
///////////////////////////////////
using System;
using System.Windows.Forms;
using System.Drawing;
using Dices; //解説:これでDice.dllをロードし、中のnamespace Dicesクラスを呼び込みます。
namespace TestDice
{
public partial class AppForm : Form
{
Dice dice1, dice2, dice3; //Diceコントロール(解説:ボタンコントロールから派生させています。)
Button rollbtn, extbtn; //ボタンコントロール
[STAThread] //解説:お忘れなく。
public static void Main()
{
Application.Run(new AppForm());
}
///////////////////////////////
//Diceコントロール(Dices.dll)
///////////////////////////////
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Resources; //ResourceManagerを使う為
using System.IO; //Streamを使う為
namespace Dices
{
public class Dice : Button //解説:ボタンコントロールから派生させる(注)ことで作成を簡単にしています。
{ //注:このようにするとカスタムコントロールが簡単に作れます。 //賽の目(解説:出た目は1-6なので整数にします。)
public int roll; //ビットマップ(解説:賽の目をビットマップ配列に入れます。)
Bitmap[] bmpD = new Bitmap[6]; //コンストラクター
public Dice()
{ //このDLLのアッセンブリーを取得する
System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); //ダイスの目のイメージを読み込む
ResourceManager rm = new ResourceManager("Dice", asm); //ResourceManagerインスタンスの作成
bmpD[0] = (Bitmap)rm.GetObject("D1");
bmpD[1]= (Bitmap)rm.GetObject("D2");
bmpD[2] = (Bitmap)rm.GetObject("D3");
bmpD[3] = (Bitmap)rm.GetObject("D4");
bmpD[4] = (Bitmap)rm.GetObject("D5");
bmpD[5] = (Bitmap)rm.GetObject("D6"); //さいころの初期値は1
//this.Image = bmpD[0]; //イメージレイアウトが指定できない
this.BackgroundImageLayout = ImageLayout.Zoom;
this.BackgroundImage = bmpD[0]; //押し下げられた時の処理
this.Click += Dice_Click;
} //デストラクター
~Dice()
{ //ビットマップを廃棄(解説:C#はいずれガーベージコレクションで廃棄するのでしょうが、明示的に廃棄します。)
bmpD[0].Dispose();
bmpD[1].Dispose();
bmpD[2].Dispose();
bmpD[3].Dispose();
bmpD[4].Dispose();
bmpD[5].Dispose();
} //Diceがクリックされた時の処理
private void Dice_Click(object sender, EventArgs e)
{ //投賽音
DiceSound(); //解説:先ず投賽音を鳴らします。 //賽を振る
Roll();
} //乱数を使用してさいころの目を返す
public int Roll()
{ //乱数の初期化(解説:毎回同じ乱数配列にならないよう実施時間で変えます。)
Random rand = new Random((int) DateTime.Now.Ticks & 0x0000FFFF);
for(int i = 0; i < 10; i++)
{
roll = rand.Next(6);
this.BackgroundImage = bmpD[roll]; this.Refresh(); //Invalidate() + Update()の効果がある。
//解説:この"this.Refresh();"がないと賽の目がくるくると変化しません。
System.Threading.Thread.Sleep(50); //好みに応じてwaitを掛ける。
}
return roll + 1;
} //Dice Roll時の音 //解説:何も書かないとtrueで"DiceSound1.wav"、falseだと"DiceSound2.wav"になります。
public void DiceSound(bool res = true)
{ /* //解説:外部waveファイルから読み取るにはこのように書きます。
string soundl_file = "DiceSound1.wav";
if(!res) soundl_file = "DiceSound2.wav";
//サウンドプレイヤーにwavファイルを読み込む
System.Media.SoundPlayer player = new System.Media.SoundPlayer(soundl_file);
*/ //このプログラムのアッセンブリーを取得する
System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); //Dice.resourcesを読み込む
ResourceManager rm = new ResourceManager("Dice", asm); //ResourceManagerインスタンスの作成 //Waveファイル用Streamクラスインスタンスsound
Stream sound;
if(res)
sound = new MemoryStream((byte[])rm.GetObject("DiceSound1"));
else
sound = new MemoryStream((byte[])rm.GetObject("DiceSound2")); //サウンドプレイヤーにWaveストリームを読み込む
System.Media.SoundPlayer player = new System.Media.SoundPlayer(sound); //解説:メディアプレイヤーのこの手軽さがC#の本領発揮というところでしょう。
以上でした。自分で動かしていると、41 x 41の迷路でも結構時間がかかるので、途中で中断せざるを得ない局面がままあったことから、この改造を行いました。まぁ、仕様を変更してこっちのプログラムを組みなおすと、あっちも手を入れなくてはならない、というように、DLL、アプリ共に見直しが必要で結構手がかかることが分かりました。(爆)
///////////////////////////////////////
//迷路コントロールテストプログラム
///////////////////////////////////////
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection; //Assemblyを使う為
using Maze_DLL; //Mazeクラスを使う為 //解説:Maze_DLLはより多くのdllを使いますが、ここで書く必要はありません。
namespace TestMaze
{ /////////////////////////////////////////////////////////////
//AppFormクラス(迷路コントロールのテスト用フォーム)
/////////////////////////////////////////////////////////////
public partial class AppForm : Form
{ //表示切替フラグ
bool Is3D = true; //進行方向
int WhereToGo = 1; //上-0、右-1、下-2、左-3 //迷路コントロール(解説:これが今回作った迷路コントロールです。)
Maze maze; //ボタンコントロール
Button btnDisp, btnUp, btnDown, btnLeft, btnRight, btnExit;
[STAThread] //解説:マルチスレッドアプリ以外はこれをつけましょう。
public static void Main() //解説:これが本アプリのエントリーポイントメソッドです。
{
AppForm ap = new AppForm();
Application.Run(ap);
}
/////////////////////////////////////////////////////////
//迷路ゲームプログラム
//作成:棒倒し法、穴開け法、壁伸ばし法
//解法:https://ja.wikipedia.org/wiki/%E8%BF%B7%E8%B7%AF
/////////////////////////////////////////////////////////
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Resources; //ResourceManagerを使う為
using System.Collections.Generic; //Listを使う為
using Atelier; //Atelier.dllを使う為
namespace Maze_DLL
{ //////////////////////////////////////////////////////////////
// 迷路クラス(迷路コントロールをDLL化したもの)
//使い方:インスタンスをコントロールとしてフォームに付加する。
//////////////////////////////////////////////////////////////
public class Maze : Panel //PictureBoxの枠となるPanelから派生
{ //////////////////////////
//クラス、変数、プロパティ
//////////////////////////
//通路・壁情報
const int Path = 0;
const int Wall = 1; //セル情報
private class Cell
{
public int X {get; set;}
public int Y {get; set;}
} //方向
const int dirUp = 0;
const int dirRight = 1;
const int dirDown = 2;
const int dirLeft = 3; /////////////////
//迷路関連データ
/////////////////
//迷路の基準規模
private int UNIT = 16; //壁、通路一単位のピクセル数(Bitmapオリジナルは16 x 16)
private int mzWidth, mzHeight; //迷路のサイズ //2次元配列の迷路情報
private int[,] MazeData; //穴掘り開始候補座標
private List<Cell> StartCells; //迷路表示切替フラグ
bool mzIs3D = true; //迷路出口の位置
Cell mzExit; //迷路探索者の位置
Cell mzWhereIam; //迷路探索者の進行方向
int mzWhereToGo = 1; //上-0、右-1、下-2、左-3 ///////////////////////
//迷路関連コントロール
///////////////////////
private PictureBox picBox; //ピクチャーボックスコントロール
private Easel easel; //描画を行うEaselオブジェクト ///////////////////////////
//迷路関連ビットマップ画像
///////////////////////////
private Bitmap bmpBack, bmpBall, bmpBrick, bmpExit; ////////////////////////////////////////////////////
//コンストラクタ(引数がない場合の初期値は41 x 41)
////////////////////////////////////////////////////
public Maze(int width = 41, int height = 41)
{ //幅、高さが5未満のサイズはエラーで中断させる
if(width < 5 || height < 5)
{
throw new ArgumentOutOfRangeException();
} //幅、高さが偶数の場合は強制的に+1で奇数に変更する
if(width % 2 == 0)
width++;
if(height % 2 == 0)
height++; //迷路情報を初期化
mzWidth = width;
mzHeight = height;
MazeData = new int[mzWidth, mzHeight];
StartCells = new List<Cell>(); //迷路探索者の初期位置
mzWhereIam = new Cell();
mzWhereIam.X = 1;
mzWhereIam.Y = 1; //迷路出口の初期位置
mzExit = new Cell();
mzExit.X = mzWidth - 2;
mzExit.Y = mzHeight - 2;
if(mzWidth != 41 || mzHeight != 41)
mzSetUNIT(); //デフォルト初期値でない場合、UNIT値を変更する必要がある //コントロール本体(好みで変更可)
this.BorderStyle = BorderStyle.Fixed3D;
this.AutoScroll = true; //スクロールバー付
this.Width = mzWidth * UNIT + 4; //デフォルト初期値は660(656 + 4)
this.Height = mzHeight * UNIT + 4; //デフォルト初期値は660(656 + 4) //描画先とするEaselオブジェクトを作成する
easel = new Easel(this.ClientSize.Width, this.ClientSize.Height); //ピクチャーボックスコントロール
picBox = new PictureBox(); //枠の中のPictureオブジェクトの作成
picBox.Location = new Point(0, 0); //枠内の位置
picBox.SizeMode = PictureBoxSizeMode.AutoSize; //画像サイズでPictureBoxの大きさが変更される
picBox.Image = easel.Canvas; //PictureBoxにEaselオブジェクトを貼り付ける //Maze(Panel)にPictureBoxを追加
this.Controls.Add(picBox); //picBoxをpanelの子にする //Mazeサイズ変更時の処理
this.SizeChanged += mzSizeChanged; //このプログラムのアッセンブリーを取得する
System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); //ResourceManagerインスタンスの作成
ResourceManager rm = new ResourceManager("Maze", asm); //Bitmapを読み込む
bmpBack = (Bitmap)rm.GetObject("Back");
bmpBall = (Bitmap)rm.GetObject("Ball");
bmpBall.MakeTransparent(Color.Black);
bmpBrick = (Bitmap)rm.GetObject("Brick");
bmpExit = (Bitmap)rm.GetObject("Exit");
bmpExit.MakeTransparent(Color.Black);
} ///////////////
//デストラクタ
///////////////
~Maze()
{
bmpBack.Dispose();
bmpBall.Dispose();
bmpBrick.Dispose();
bmpExit.Dispose();
} /////////////////////////////
//Mazeサイズが変更された場合
/////////////////////////////
private void mzSizeChanged(object sender, EventArgs e)
{
mzSetUNIT();
easel.Resize(this.ClientSize.Width, this.ClientSize.Height); //解説:Mazeの画像ビットマップのリサイズ
Display(mzIs3D, mzWhereToGo); //解説:Mazeの画像をリサイズして再描画
picBox.Image = easel.Canvas;
} /////////////////////////////////
//Mazeのクライアントエリアサイズ
//に基づきUNITを決定する
/////////////////////////////////
private void mzSetUNIT()
{
int w = this.ClientSize.Width / mzWidth;
int h = this.ClientSize.Height / mzHeight;
UNIT = (w < h) ? w : h; //Maze内に表示が収まるように小さい方を選択
} /////////////////////////
//Mazeのサイズを取得する
/////////////////////////
public Size mzGetSize()
{
return new Size(mzWidth, mzHeight);
} ///////////////
//迷路生成処理
///////////////
public int[,] GenerateMaze()
{ //全てを壁で埋める
//穴掘り開始候補(x,yともに偶数)座標を保持しておく
for(int y = 0; y < this.mzHeight; y++)
{
for(int x = 0; x < this.mzWidth; x++)
{
if(x == 0 || y == 0 || x == this.mzWidth - 1 || y == this.mzHeight - 1)
{
MazeData[x, y] = Path; // 外壁は判定の為通路にしておく(最後に戻す)
}
else
{
MazeData[x, y] = Wall;
}
}
} //穴掘り開始
Dig(1, 1); //外壁を戻す
for(int y = 0; y < this.mzHeight; y++)
{
for(int x = 0; x < this.mzWidth; x++)
{
if(x == 0 || y == 0 || x == this.mzWidth - 1 || y == this.mzHeight - 1)
{
MazeData[x, y] = Wall;
}
}
}
return MazeData;
} /////////////////////////////
//迷路の座標(x, y)に穴を掘る
/////////////////////////////
private void Dig(int x, int y)
{ //指定座標から掘れなくなるまで堀り続ける
Random rnd = new Random();
while(true)
{ //掘り進めることができる方向のリストを作成
List<int> directions = new List<int>();
if(this.MazeData[x, y - 1] == Wall && this.MazeData[x, y - 2] == Wall)
directions.Add(dirUp);
if(this.MazeData[x + 1, y] == Wall && this.MazeData[x + 2, y] == Wall)
directions.Add(dirRight);
if(this.MazeData[x, y + 1] == Wall && this.MazeData[x, y + 2] == Wall)
directions.Add(dirDown);
if(this.MazeData[x - 1, y] == Wall && this.MazeData[x - 2, y] == Wall)
directions.Add(dirLeft); //掘り進められない場合、ループを抜ける
if(directions.Count == 0) break; //指定座標を通路とし穴掘り候補座標から削除
SetPath(x, y); //掘り進められる場合はランダムに方向を決めて掘り進める
int dirIndex = rnd.Next(directions.Count); //決まった方向に先2マス分を通路とする
switch(directions[dirIndex])
{
case dirUp:
SetPath(x, --y);
SetPath(x, --y);
break;
case dirRight:
SetPath(++x, y);
SetPath(++x, y);
break;
case dirDown:
SetPath(x, ++y);
SetPath(x, ++y);
break;
case dirLeft:
SetPath(--x, y);
SetPath(--x, y);
break;
}
} //どこにも掘り進められない場合、穴掘り開始候補座標から掘りなおし
//候補座標が存在しないとき、穴掘り完了
Cell cell = GetStartCell();
if(cell != null)
{
Dig(cell.X, cell.Y);
}
} ///////////////////////////////////////////////////
//座標を通路とする(穴掘り開始座標候補の場合は保持)
///////////////////////////////////////////////////
private void SetPath(int x, int y)
{
this.MazeData[x, y] = Path;
if(x % 2 == 1 && y % 2 == 1)
{ //穴掘り候補座標
StartCells.Add(new Cell() { X = x, Y = y });
}
} /////////////////////////////////////
//穴掘り開始位置をランダムに取得する
/////////////////////////////////////
private Cell GetStartCell()
{
if(StartCells.Count == 0) return null;
//ランダムに開始座標を取得する
Random rnd = new Random();
int index = rnd.Next(StartCells.Count);
Cell cell = StartCells[index];
StartCells.RemoveAt(index);