こんにちは、きうちです。
うだるような暑さが続きますが、いかがお過ごしでしょうか?
暑いのはかなわないですが、暑いからこそビールが美味い。
ビアガーデンとか久々に行きたいなー・・・とか考えながら日々の業務をこなしております^^
★ ★ ★
今回は、「16パズル」を作ってみたいと思います。
ご存じとは思いますが、4×4のフィールドに1~15の数字が描かれた(あるいは絵が描かれた)四角いピースが置かれていて、ランダムな状態から綺麗な順番に並べ替える、というあれです。
私は「16パズル」という名前で憶えているのですが…WikiPediaさんによると、「15パズル」のようですね。
https://ja.wikipedia.org/wiki/15%E3%83%91%E3%82%BA%E3%83%AB
まあ、このブログでは「16パズル」と記載します。
そんなに難しくはないと思いますので、例によって自力で組み立ててみたいと思います!
言語は例によってC#にします。Windowsフォームアプリとして作成します。
今回はピクチャーボックスを1つ配置して、そこに描画することにします。
16パズル・・・1~15の数字が書かれた(あるいは絵柄などが描かれた)15個のピースを所定の場所に移動させるパズルゲームですが、
この世界を表現するために、フォームクラスに4×4のint型の2次元配列 cells を用意します。
そして SetupCells というメソッドを作ってピースを並べる処理を実行させます。
1~16のピースを cells に並べていきます。そのあと、16は不要なので消します。
コンストラクタにて SetupCells を呼び出します。
public partial class Form1 : Form { private readonly int[,] cells = new int[4, 4]; public Form1() // コンストラクタ { InitializeComponent(); SetupCells(); } private void SetupCells() // 準備 { for (int x = 0; x < 4; x++) // ピースを並べる { for (int y = 0; y < 4; y++) { cells[x, y] = y * 4 + x + 1; } } cells[3, 3] = 0; // 一番右下のピースをなくす } }
続いて、これを画面に描画するためのイベントメソッドを用意します。
また、コンストラクタの最後でRefreshを実行し、画面を描画させます。
public Form1() // コンストラクタ { InitializeComponent(); SetupCells(); Refresh(); } ... private void pictureBox1_Paint(object sender, PaintEventArgs e) // ピクチャーボックス描画イベント { for (int x = 0; x < 4; x++) { for (int y = 0; y < 4; y++) { if (cells[x, y] != 0) { e.Graphics.FillRectangle(Brushes.AliceBlue, x * 64, y * 64, 63, 63); e.Graphics.DrawString(cells[x, y].ToString("D2"), new Font("MS ゴシック", 32), Brushes.Black, x * 64, y * 64 + 8); } } } }
さて、実行させてみましょう。
ピースが順番に並びました!
★ ★ ★
続いて、ピースを動かせるようにします。
ピースがある箇所をクリックすると、そのピースが動ける方向に動くことにします。何もないところをクリックするか、移動できないピースをクリックした場合は何も起きないことにします。
イベントはMouseClickでやります。
実際に動かす処理はイベントメソッドとは分けて記述します。
private void pictureBox1_MouseClick(object sender, MouseEventArgs e) // マウスクリック時処理 { int x = e.X / 64; int y = e.Y / 64; MovePiece(x, y); } private void MovePiece(int x, int y) // ピースを動かす { if (cells[x, y] == 0) return; // 何もないところをクリックしたら何もせずreturn if (x > 0 && cells[x - 1, y] == 0) // クリックされた位置の左が空の場合はそちらへ移動 { cells[x - 1, y] = cells[x, y]; cells[x, y] = 0; } else if (x < 3 && cells[x + 1, y] == 0) // クリックされた位置の右が空の場合はそちらへ移動 { cells[x + 1, y] = cells[x, y]; cells[x, y] = 0; } else if (y > 0 && cells[x, y - 1] == 0) // クリックされた位置の上が空の場合はそちらへ移動 { cells[x, y - 1] = cells[x, y]; cells[x, y] = 0; } else if (y < 3 && cells[x, y + 1] == 0) // クリックされた位置の下が空の場合はそちらへ移動 { cells[x, y + 1] = cells[x, y]; cells[x, y] = 0; } Refresh(); }
実行してみます。
動かせるようになりました!
★ ★ ★
ランダムに並んだ状態から、ゴール(綺麗に並んでいる状態)を目指せるようにしたいですね。
というわけで、そうする処理を追加しましょう。
Shuffleというメソッドを追加してそこに処理を書きます。
コンストラクタで、SetupCellsの次にそれを呼びます。
public Form1() // コンストラクタ { InitializeComponent(); SetupCells(); Shuffle(); // 追加 Refresh(); } private void Shuffle() // シャッフル { for (int i = 0; i < 5000; i++) { int x = random.Next(0, 4); int y = random.Next(0, 4); MovePiece(x, y); } }
ランダムに位置を決定し、そのピースを動かそうとする、というのを5000回試行する処理になっています。
本当は位置決定は穴が開いているところの周辺4ピースのいずれかにするのがいいのでしょうけれども、まあ面倒なので(笑)
実行してみます。
ランダムになりました!
★ ★ ★
といったところで、今日はここまで。
後編では、数字じゃなくて何か図柄が描かれたものにしようかなー・・・と思っています。
それでは!