前回は、上キーを押したときのみの処理を書いていましたが、上下左右のキーに対応しました。
これに伴って、上下左右のキーを押したとき、各セルの移動先を求める関数を切り出しました。
移動先を求めるのはgetDestPos()メソッドで、これを利用してセル移動を行うmoveCell()メソッドを実装しています。
他には、方向指定がC#のKeys列挙体の定義を流用していたため、専用のDIR列挙体を作っているなど、細かいところを修正しました。
using System; using System.Collections.Generic; using System.Data; using System.Windows.Forms; using System.Diagnostics; namespace Mock2048 { enum DIR { UP, RIGHT, DOWN, LEFT, }; public partial class Form1 : Form { const int BOARD_SIZE = 4; // 盤面の情報 private int[,] board = new int[BOARD_SIZE,BOARD_SIZE]; public Form1() { InitializeComponent(); } //********************************************************************* /// <summary> 画面表示時のハンドラ /// </summary> //********************************************************************* private void Form1_Load( object sender, EventArgs e ) { // Formコントロール自身がキー入力を取得可能とする this.KeyPreview = true; //盤面の初期化 initBoard(); // 盤面を表示する displayBoard(); } //********************************************************************* /// <summary> キー入力時のハンドラ /// </summary> //********************************************************************* private void Form1_KeyDown( object sender, KeyEventArgs e ) { switch (e.KeyCode) { case Keys.Up: moveCell( DIR.UP ); break; case Keys.Right: moveCell( DIR.RIGHT ); break; case Keys.Down: moveCell( DIR.DOWN ); break; case Keys.Left: moveCell( DIR.LEFT ); break; } // 盤面を表示する displayBoard(); } //********************************************************************* /// <summary> 盤面の初期化(テストデータのセット) /// </summary> //********************************************************************* private void initBoard() { board[0,0] = 2; board[0,3] = 2; board[1,1] = 8; board[2,0] = 4; board[2,2] = 4; board[3,0] = 2; board[3,1] = 2; board[3,3] = 8; } //********************************************************************* /// <summary> 盤面を画面に表示させる /// </summary> //********************************************************************* private void displayBoard() { string boardData = ""; // すべての行のデータを出すまで繰り返し for (int y = 0; y < 4; y++) { // 1行分のデータを出力 for (int x = 0; x < 4; x++) { boardData += "[" + String.Format("{0, 2}", board[x,y]) + "] "; } boardData += Environment.NewLine; boardData += Environment.NewLine; } txtLog.Text = boardData; txtLog.Select(0,0); txtLog.ReadOnly = true; } //********************************************************************* /// <summary> 指定された方向に移動させる /// </summary> /// <param name="keyCode"></param> //********************************************************************* private void moveCell( DIR dir ) { // 入力されたキーを判定する switch ( dir ) { case DIR.UP: // 2~4列目に対し上方向のスライドを試みる for (int y = 1; y < BOARD_SIZE; y++) { for (int x = 0; x < BOARD_SIZE; x++) { moveCell( x, y, DIR.UP ); } } break; case DIR.DOWN: // 1~3列目に対し下方向のスライドを試みる for (int y = BOARD_SIZE-2; y >= 0; y--) { for (int x = 0; x < BOARD_SIZE; x++) { moveCell( x, y, DIR.DOWN ); } } break; case DIR.LEFT: // 2~4行目に対し左方向のスライドを試みる for (int y = 0; y < BOARD_SIZE; y++) { for (int x = 1; x < 4; x++) { moveCell( x, y, DIR.LEFT ); } } break; case DIR.RIGHT: // 1~3行目に対し右方向のスライドを試みる for (int y = 0; y < BOARD_SIZE; y++) { for (int x = BOARD_SIZE-2; x >= 0; x--) { moveCell( x, y, DIR.RIGHT ); } } break; default: //txtLog.Text = ""; break; } } //********************************************************************* /// <summary> 指定された方向にセルをスライドさせる /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="dir"></param> //********************************************************************* private void moveCell( int x, int y, DIR dir ) { int endX; int endY; bool isDuplicate; // 移動先のセル位置を求める getDestPos( x, y, dir, out endX, out endY, out isDuplicate ); // セルを移動 int targetVal = board[x,y]; board[x,y] = 0; board[endX,endY] = targetVal * (isDuplicate ? 2 : 1 ); } //********************************************************************* /// <summary> 指定された方向にセルをスライドさせた時の移動先を求める /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="dir"></param> /// <param name="endX"></param> /// <param name="endY"></param> /// <param name="isDuplicate"></param> //********************************************************************* private void getDestPos( int x, int y, DIR dir, out int endX, out int endY, out bool isDuplicate ) { // initialize endX = x; endY = y; isDuplicate = false; // 指定されたセルの値を取得 int targetCellVal = board[x,y]; if (targetCellVal == 0) { return; } // 移動方向を元に探索方向のオフセットを決める int dx = 1; int dy = 1; switch ( dir ) { case DIR.UP: dx = 0; dy = -1; break; case DIR.RIGHT: dx = 1; dy = 0; break; case DIR.DOWN: dx = 0; dy = 1; break; case DIR.LEFT: dx = -1; dy = 0; break; } // 何かにぶつかるまで探索する while (true) { if (endX + dx < 0 || endY + dy < 0 || endX + dx >= BOARD_SIZE || endY + dy >= BOARD_SIZE) { // 壁にぶつかった -> 1つ手前の場所でストップ isDuplicate = false; break; } else if (board[endX + dx, endY + dy] != 0) { // 他のセルにぶつかった if (targetCellVal == board[endX + dx, endY + dy]) { // 衝突先が同じ値だった -> 重ねる endX += dx; endY += dy; isDuplicate = true; break; } else { // 衝突先が異なる値だった -> 1つ手前の場所でストップ isDuplicate = false; break; } } else { // 何にもぶつからなかった -> さらに次の位置をチェック endX += dx; endY += dy; continue; } } //Debug.WriteLine( "セルの移動を行います [" + x + ", " + y + "] -> [" + endX + ", " + endY + "] dup=" + isDuplicate ); } } } |
今回作ったプログラムのexeも置いときます。
キーボードのカーソルキーを押して操作してみてください。うまく操作すると、32の数字を作ることができます。
Mock2048_20160127.zip
次回は、Boardの概念をクラスに分けるか、もしくは全体のゲームの進行制御を作る予定です。
関連記事
コメントを残す