C#で2048ゲームのクローンを作る[その2]

前回は、上キーを押したときのみの処理を書いていましたが、上下左右のキーに対応しました。

これに伴って、上下左右のキーを押したとき、各セルの移動先を求める関数を切り出しました。
移動先を求めるのは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の概念をクラスに分けるか、もしくは全体のゲームの進行制御を作る予定です。

サクラエディタで制御文字を入力する方法

ASCIIコードには、通常の数字やアルファベット以外にCR,LF,STX,ETXなどの制御文字があります。
サクラエディタで改行やタブの制御文字は、簡単に入力できるのですが、STX,ETXなどの文字は簡単に入力できません。

サクラエディタで制御文字を入力するには、下記より制御文字の入力ダイアログが表示できます。

編集->挿入->コントロールコード入力


もし、キーボードだけで操作したい場合は”Alt+E -> I -> C”の順にキー入力すればOKです。



ダイアログの一覧から入力したい制御文字をクリックすれば制御文字が入ります。


正しく入力できたかは、ウィンドウ下のステータスバーに文字コードが出るので、そこで確認可能です。

ただし、この方法で改ページの制御文字(0x0C:^L)を入力しても、なぜかサクラエディタは改ページのコードを無視するらしく、正しくページが分かれてくれませんでした。
秀丸エディタなどは正しく認識してくれるので、この辺は少し残念な感じです。

WindowでTotoiseSVNだけ使ってSVNサーバを用意する

Windowの環境で、TotoiseSVNを使用してSVNサーバを作ってみます。
ローカルにサーバ環境の作る方法を覚えておくと、普段はLinux上にSVNサーバを持っているけど普段使わないコマンドを使用したい時など、事前にローカル環境でコマンドの実行を試してみることができるので便利です。

まずは、リポジトリを作ります

set PATH=%PATH%;C:\Program Files\TortoiseSVN\svn-win32-1.8.13\bin
mkdir c:\home2\test_svn
cd c:\home2\test_svn
svnadmin create test_repo



次にユーザを作成し、svnへのcommit権限を与えます

1.C:\home\test_svn\test_repo\conf\passwd に行を追加します

-------------------
[users]
# harry = harryssecret
# sally = sallyssecret
 
user=pass
-------------------



2.C:\home\test_svn\test_repo\conf\svnserve.confのコメントを外します

-------------------
[general]
anon-access = read
auth-access = write
 
password-db = passwd
-------------------




svnサーバのプログラムを実行します。
コマンドを実行すると、そのまま応答が無くなりますが、ウインドウは閉じずに置いておきます。

svnserve.exe --daemon --root c:\home\test_svn



別のウィンドウを開き、作ったリポジトリをチェックアウトします。
下記の例ではコマンドラインで作業していますが、TortoiseSVNおGUIで作業してもOKです。

set PATH=%PATH%;C:\Program Files\TortoiseSVN\svn-win32-1.8.13\bin
cd /d c:\home\test_client
svn co svn://localhost/test_repo




ここまで来たら、リポジトリへ操作をいろいろ行ってみます。
1.コミットする

echo hello > test.txt
 
svn status
?       test.txt
 
svn add test.txt
A       test.txt
 
svn commit --username user --password pass -m "test commit"
追加しています              test.txt
ファイルのデータを送信しています .
Committed revision 1.
 
svn status    #変更なしなので、何も表示されません



2.コミットしたファイルを削除して、revertで元に戻してみる

del test.txt
 
svn status
!       test.txt
 
svn revert -R .
'test.txt' を元に戻しました
 
svn status



というわけで、これでWindownsのローカル環境上にSVNサーバを作ることができました。

C#で2048ゲームのクローンを作る[その1]

これから勉強をかねて、2048というゲームのクローンをWinFormで作ってみようと思います。

2048って何?


一時期ブームになったスマホのゲームアプリで、パネルをスライドさせながら大きな数字を作っていくゲームです。ルールは説明するより、動画を見てもらったほうが早いです。


個人的にはこのゲーム、結構プレイしていて最高で8192まで行った事があります。



作成ルール

本当は一気に作ってしまいのですが、時間が無いので下記のルールで少しづつ進めていきます。

毎週何か作る。本当な毎日少しづつ進めたいけど仕事があるので、週に3回以上は最低目標とする。

作成中のプログラムをBlogにさらす。本当ならいったん全部作ってしまってから、キレイに順序だてて説明すべきなのだけど、それだとモチベーションが続かなさそう。なので、試作目的で後で消す予定のコードだとしても一旦アップしてしまう。

ネットで2048cloneの作り方は検索できるけど、勉強の為にあえて見ずに作ってみる。


今日のコード

と、言うわけでさっそく今日の成果です。
とりあえず今回はイメージをつかむために、下記の試作をして見ました。

・最初の盤面は決まっている。
・カーソルキーの上を押したら、上方向にスライドさせる。
・スライドさせても新しいパネルは出現しない。
・画面表示はまだ作らない。(TextBoxに盤面データをダンプするだけ)

なので、プログラムが起動したらカーソルの上キーを押すだけの動作確認状態です。
現状のロジックだと、2回上を押すと2のパネルが消えてしまうバグがあるとう中途半端な状態ですが、続きはまた次回にします。

パネルのスライド処理が地味に面倒です…

using System;
using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;
 
namespace Mock2048 {
    public partial class Form1 : Form {
        // 盤面の情報
        private int[,] board = new int[4,4];        
 
        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 ) {
            moveCell( e.KeyCode );
 
            // 盤面を表示する
            displayBoard();
        }
 
        //*********************************************************************
        /// <summary> 盤面の初期化(テストデータのセット)
        /// </summary>
        //*********************************************************************
        private void initBoard() {
            board[2,0] = 4;
            board[3,0] = 2;
            board[3,1] = 2;
 
            board[2,2] = 4;
            board[3,3] = 2;
 
        }
 
        //*********************************************************************
        /// <summary> 盤面を画面に表示させる
        /// </summary>
        //*********************************************************************
        private void displayBoard() {
            string boardData = "";
 
            // すべての行のデータを出すまで繰り返し
            for (int y = 0; y < 4; y++) {
                // 1行分のデータを出力
                for (int x = 0; x < 4; x++) {
                    boardData += board[x,y];
                }
                boardData += Environment.NewLine;
            }
 
            txtLog.Text = boardData;
        }
 
        //*********************************************************************
        /// <summary> 指定された方向に移動させる
        /// </summary>
        /// <param name="keyCode"></param>
        //*********************************************************************
        private void moveCell( Keys keyCode ) {
 
            // 入力されたキーを判定する
            switch ( keyCode ) {
                case Keys.Up:
                    // 2~4列目に対して上方向のスライドを試みる
                    for (int y = 1; y < 4; y++) {
                        for (int x = 0; x < 4; x++) {
                            int targetCellVal = board[x,y];
                            if ( targetCellVal == 0 ) {
                                continue; // 空セルは何もしない
                            }
 
 
                            // 上方向に移動させる
                            bool isMoved = false;
                            for ( int endY = y-1; endY >= 0; endY-- ) {
                                if ( board[x,endY] == 0 ) {
                                    continue; // 空セルなら、さらに移動先を探索
                                }
 
                                // 空セルで無ければ、合体or衝突させる
                                if ( targetCellVal == board[x,endY] ) {
                                    // 同じ値なら合体
                                    board[x,endY] = targetCellVal*2;
                                    board[x,y] = 0;
                                    isMoved = true;
                                    break;
                                } else {
                                    // 異なる値なら1つ手前のところまで移動
                                    board[x,endY+1] = targetCellVal;
                                    board[x,y] = 0;
                                    isMoved = true;
                                    break;
                                }                                                           
                            }
                            if ( isMoved == false ) {
                                // 壁まできたら、壁まで移動
                                board[x,0] = targetCellVal;
                                board[x,y] = 0;
                                break;
                            }
 
                        }
                    }
 
                    //txtLog.Text = "[UP]";
                    break;
                case Keys.Down:
                    //txtLog.Text = "[DOWN]";
                    break;
                case Keys.Left:
                    //txtLog.Text = "[LEFT]";
                    break;
                case Keys.Right:
                    //txtLog.Text = "[RIGHT]";
                    break;
                default:
                    //txtLog.Text = "";
                    break;
            }
        }
 
    }
}

[C#]WinFormでゲーム作成時、カーソル入力を取得する方法

Windows上で.Net Frameworkを使用してゲームなどを作るとき、キー入力を取得したい場合があります。
このような場合、画面内のTextBoxなどにフォーカスが当たっていると、キー入力をフォーカスが当たったコントロールが処理してしまいます。

このような場合は、FormのKeyPreviewをtrueにするとよいです。
実際のキー入力チェック処理は、FormのKeyDownイベントで取得すると便利です。

using System;
using System.Windows.Forms;
 
namespace Test01 {
    public partial class Form1 :Form {
        public Form1() {
            InitializeComponent();
        }
 
        private void Form1_Load( object sender, EventArgs e ) {
            // Formコントロール自身がキー入力を取得可能とする
            this.KeyPreview = true;
 
        }
 
        private void Form1_KeyDown( object sender, KeyEventArgs e ) {
            // 入力されたキーを判定する
            switch ( e.KeyCode ) {
                case Keys.Up:
                    textBox1.Text = "[UP]";
                    break;
                case Keys.Down:
                    textBox1.Text = "[DOWN]";
                    break;
                case Keys.Left:
                    textBox1.Text = "[LEFT]";
                    break;
                case Keys.Right:
                    textBox1.Text = "[RIGHT]";
                    break;
                default:
                    textBox1.Text = "";
                    break;                        
            }
        }
 
    }
}

WindowsからAWS CodeCommitを使う(TortoiseGit使用)

AWSにてプライベートに使用できるgitのリポジトリサービスであるCodeCommitがリリースされました。

このCodeCommitの料金体系ですが、https://aws.amazon.com/jp/codecommit/pricing/に記載されているとおり以下の範囲では、なんと無料で使用可能です。
・5 人のアクティブユーザー
・50 GB のストレージ/月
・10,000 件の Git リクエスト

個人のプログラムを管理する程度であれば、無料の範囲で十分なので、かなり太っ腹なサービスです。
Githubのようなオープンなリポジトリではなく、個人でプライベートに使いたい場合には最適です。

今回はCodeCommitに対して、Windowsからアクセスできるよう設定の仕方を説明します。
CodeCommitの記事は他にもあるのですが、コマンドラインを使った説明が多かったため、今回の説明ではGUIのみで作業してみます。


Gitクライアントのインストールと、キーファイルの作成

まずは、手元のWindows環境にGitクライアントをインストールします。
今回使用したバージョンはTortoiseGitのver1.8.16と、Gitのver2.7.0です。

それぞれ、下記の場所からDLできます。
https://tortoisegit.org/download/
http://git-scm.com/


インストールしたら、まずユーザ認証に使用する公開鍵と秘密鍵を作成します。
Gitインストール時に一緒に入るPuTTY Key Generator(puttygen.exe)を起動します。



起動したら、パラメータがSSH-2 RSA,2048bitになっていることを確認しGenerateをクリックします。

すると、マウスを動してとのメッセージが表示されるので、ウィンドウ内で適当にマウスを動かします。
動かすごとにゲージが伸びていき、最後までゲージが伸びるとキーが生成されます。
(マウスの動かし方を元に、暗号化キーを決めています)


完了すると以下の画面になります。
パスワード(Key Pasphrase)を2か所入れて、Save private keyをクリックします。


名前は今回の説明では、CodeCommit.ppkという名前で保存します。
これが、CodeCommitにログインする際に必要な秘密鍵になります。



次に、公開鍵を保存します。
ウィンドウの上にあるこの部分をコピーして…

エディタに張り付けて、保存します。

今回は、CodeCommit_OpenSSH.pubの名前で保存しました。この情報はCodeCommitにアカウントを作るときに使用します。1行が長いので、最後の文字まできちんと貼り付けできたか確認してさい。



AWS CodeCommit用のアカウント作成

次に、gitにログインするアカウントを作ります。
awsのコンソールにログインし、メニューからIdentity and Access Managementを選びます。



ダッシュボードのユーザより、新規ユーザの作成をクリックします。



好きな名前を入れてユーザを作成してください。
ユーザ名を入力し、作成ボタンをクリックします。今回は分かりやすくCodeCommitUserとしましたが、複数人で作業する場合はCodeCommitUser_yamada_taroのような感じで、名前が分かるようにしておいたほうが管理しやすいです。



ユーザーセキュリティ認証情報が表示されます。
今回の作業では必要ありませんが、このユーザーセキュリティ認証情報は後からDLしなおせないので、必ず控えておいて下さい。



一覧に戻るとユーザが追加されているので、ユーザ名の部分をクリックします。



ページ下部にある”SSH 公開キーのアップロード”をクリックします。



公開キーの入力欄が表示されます。
ここで先ほど保存した公開キー(CodeCommit_OpenSSH.pubの中身)をペーストします。
秘密キー(*.ppk)のほうではないので注意してください。
貼り付けができたら、アップロードボタンをクリックします。



登録に成功したら、一覧に追加されていることを確認します。SSH キー IDの値がgitのユーザIDになるので控えておきます。下の画像だと、”APKAIJRYL635BYVTMELA”の部分です。

※ここで以下のエラーが出る場合はSSHキーの作成に失敗しています。その際はputtygenの作業からやり直してください。

 リクエストの処理中に次のエラーが発生しました:
 Invalid public key uploaded.




次に、このユーザにCodeCommitのアクセス権を付与します。
アクセス許可のタブを選択し、ポリシーのアタッチを選択します。



ポリシータイプの検索キーワードにCodeCommitと入力します。
表示された中から、”AWSCodeCommitFullAccess”にチェックを入れ、ポリシーのアタッチボタンをクリックします。この権限だと、文字通り何でもできるFullAccessの管理者アカウントになります。

ちなみにAWSCodeCommitPowerUserは、FullAccessとほぼ同じですが、リポジトリの削除ができない点だけが異なります。また、ReadOnlyは参照(ダウンロード)だけが行えます。


一覧にポリシー(アクセス権)が追加されたことを確認します。
ここまで確認できたら、アカウントの作成は完了です。




AWS CodeCommitのgitリポジトリ作成


次に、CodeCommitのサービス上にGitリポジトリを作ります。
再度AWSコンソールの一覧よりCodeCommitを選びます。



メニューが表示されたら、Get startedをクリックします(この画面は最初に1回だけ表示されます)。



リポジトリ名を入力しCreate repositoryをクリックします。説明文は省略可能ですが、何を保存しているのか後でわかるようにメモを残しておいた方が後々便利です。



一覧にリポジトリが表示されるので、右端のURLをクリックし、SSHのアドレスをコピーします。
下記の例だと、”ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/TestRepository”がリポジトリ名です。


これで、アクセスに必要なリポジトリ名と、ユーザIDが取得できました。



AWS CodeCommitのgitリポジトリへアクセス

ここまでの作業で準備が完了したので、作ったリポジトリの取得(clone)を行います。
※cloneはsvnで言うところのcheckoutに相当するものです。

リポジトリを作りたいフォルダで右クリックし、Git Cloneを選択します。



必要な情報を入力します。
1.URLにリポジトリ作成時に指定したアドレス(ssh://から始まるもの)を入れます。
2.Directoryにclone先が入っていることを確認します。
3.Load Putty KeyにPuttyGenで作成した秘密キー(*.ppk)を指定します。
入力が終わったら、OKをクリックします。



パスワードの入力ダイアログが表示されます。
ここには、puttygen.exeでキーファイル作成時に入力したpassphaseを入れます。



次はログインIDの入力ダイアログが表示されます。
ここでは、AWSにSSHキー公開鍵を登録したときに表示された、SSH キー IDを入力します。
今回の説明だと”APKAIJRYL635BYVTMELA”でしたので、これを入れます。



ここまで問題なければ、Successが表示されるはずです。Closeボタンをクリックして、画面を閉じます。



次に、動作確認のため試に何かコミットしてみます。
チェックアウトしたフォルダに何かファイルを作って下さい。



ファイルを右クリックし、TortoiseGit -> Addを選択します。



ファイルにチェックが入っていることを確認し、OKをクリックします。



Successと表示されるのを確認し、そのままローカル環境にcommitします。
Commitボタンをクリックします。



コミットメッセージを入力し、OKボタンをクリックします。



Successと表示されるのを確認し、そのままAWSのリポジトリにpushします。
左下にあるPushをクリックします。



Remoteがorign(AWSサーバ)になっていることを確認して、OKをクリックします。
orignがどこのアドレスか知りたい時は、横にあるManageボタンをクリックすると分かります。



再度IDのダイアログが表示されます。
Cloneを行ったときと同じIDを入力します。



Successと表示されるのを確認し、Closeをクリックします。


再度AWSのCodeCommitに戻り、Last Updatedが更新されていることを確認します。
リポジトリの名前をクリックし詳細を確認してみます。



DashBoardのCodeを選び、コミットしたファイルが表示されていたら成功です。
ファイル名をクリックすると、中身を見ることもできます。



以上で、Windows環境にGitクライアントをインストールし、AWS上に作ったリポジトリへのアクセスが行えました。

[Smarty]PHPでセットしたdefine(“KEY”, “value”)の定数をSmaryで表示する

PHPでは、定数をdefine()関数で定義することができます。
viewのテンプレートにSmartyを使用している場合、この定数は$smarty.constで取得可能です。

以下、コード例です。
test.php

<?php
define("MESSAGE", "hello world");



test.tpl

{$smarty.const.MESSAGE}




これで、画面にhello worldが表示されます。

C#からVBScriptのコードを呼び出す一番簡単なサンプル

C#やVB.NETでWindowsのプログラムを作っているとき、プラグインのような形で実行内容をカスタマイズしたい場合があります。きちんと作るには.dllを用意した方が良いですが、小さなツールだとそこまで大げさに作りたくない時もあります。

このような場合は、Microsoft Script Controlというライブラリを使うことで、C#のプログラムからVBScript(*.vbs)やJScript(*.js)のコードを外部スクリプトとして、呼び出すことができます。

今回はVBScriptの関数を呼び出せる最低限のプログラムサンプルを作成しました。
プログラム中のコメントに記載していますが、Microsoft Script Control 1.0の参照設定が必要です。

using System;
using System.Collections.Generic;
using System.Windows.Forms;
 
public partial class Form1 :Form {
    public Form1() {
        InitializeComponent();
    }
 
    private void button1_Click( object sender, EventArgs e ) {
 
        // VBScriptのScriptControlを取得 
        //   ※使用にはMicrosoft Script Control 1.0の参照設定が必要
        MSScriptControl.IScriptControl scriptCtrl = new MSScriptControl.ScriptControl();
        scriptCtrl.Language = "VBScript";
 
        // 実行するスクリプトを指定
        scriptCtrl.AddCode( txtScript.Text );
 
        // 関数への引数を指定
        List<object> paramList = new List<object>();
        paramList.Add( 10 );
        paramList.Add( 20 );
 
        // 名前を指定してVBScriptの関数を実行
        var result = scriptCtrl.Run( "AddValue", paramList.ToArray() );
 
        // 実行結果を画面に出力
        txtOutput.Text = result.ToString();
    }
}




実行結果は、以下のような感じで確かにVBScript実行結果が出力されています。
VBScriptスクリプト自体を単体確認する方法は、こちらの記事で説明しています。



プログラムのサンプルも置いておきます。スクリプトを変更することで出力結果が変わることを確認してみてください。
RunVbsExample1.exe

[PIC]C18コンパイラでsprintfを使う時の注意

sprintfの第二引数で指定する文字列は、文字列定数を指定する必要があります。

OKなパターン

sprintf( TmpBuff, "test%d", 10 );



NGなパターン

char pMsg[] = "test%d";
sprintf( TmpBuff, pMsg, 10 );



これは、以下の理由に起因します。
・PICはハーバードアーキテクチャを採用している。
・文字列定数はプログラムメモリ、文字列の配列はファイルレジスタに保存される。
・sprintf()の第二引数は、プログラムメモリの番地を指定する必要がある。

というわけで、変数指定はNGです。

VBScriptで関数を使う

VBScriptで関数を使うとき、最低限覚えておくことです。

1.関数はFunction、End Functionでくくる。
2.戻り値は”関数名=”の形で代入する

Function AddValue( param1, param2 )
    AddValue = param1 + param2
End Function




実行例はこちら

ソース:test.vbs

val1 = 10
val2 = 20
 
result = AddValue( val1, val2 )
Wscript.Echo "答えは" & result
 
Function AddValue( param1, param2 )
    AddValue = param1 + param2
End Function



実行結果:

> cscript test.vbs
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.
 
答えは30

NetworkSolutionsからドメインを移管する(画像アリ)



有名な海外のドメイン管理会社(レジストラ)に、NetworkSolutions.comというサイトがあります。
今回は、Network Solutionsから他のレジストラへドメインを移管するための手順を説明します。

ドメイン移管するためには、まず移管元レジストラであるNetworkSolutions.comより認証番号を発行してもらう必要があります。
認証番号は、AuthCodeとも呼ばれています。

AuthCodeの発行方法

networksolutions.comにログインし、右上のManage Accountをクリックします。



左下にある”My Domain Names”をクリックします。



すると、管理しているドメインの一覧が表示されます。画像では塗りつぶしていますがDetail for xxxxのところにドメイン名が表示されます。
移管したいドメインのTransfer Lockの右にある”Turn Off or Request Authrozation Code”のリンクをクリックします。




次の画面でStop!と警告が出ますが、気にせずContinueをクリックします。
警告の内容はユーザ引き止めの案内で、意訳すると以下のような感じです。

Stop!
Before you transfer your domain to another company, we would like to extend to you a 
special promotional offer to renew your domain. 
This is a limited time offer so please act fast to get this reneweal rate.




ストップ!
他の会社にドメインを移管する前に、ドメインリニューアルのための特別キャンペーンを紹介します。
限定キャンペーンなので今すぐにチェックしてね。





再度警告が出ますが、チェックボックスにチェックを入れた上で、Continue Transferをクリックします。
個人の公開…の部分は、ドメイン登録時に入力したドメイン管理者の情報についてかと思いますが、あたりまえのことなので特に気にしなくて良いです。

Warning!
You have just requested an auth code to transfer your domain to another company.
By transferring your domain you assume all responsibility and risk for ensuring 
you maintain ownership of your domain name.
 
Your personal contact information and details might be made public by transferring your domain.
 
Please click the box below to acknowledge your agreement with the above.




警告!
他の会社(レジストラに)にあなたが保有しているドメインのauth codeを要求しました。
あなたは、ドメインを転送することの、ドメイン名の所有権を維持と確保するための
すべての責任とリスクを負います。
 
個人の連絡先情報や詳細は、あなたのドメインを転送することによって公開されている可能性があります。
 
この内容を承認する場合は、以下のボックスをクリックして進んでください。





次に、アンケートが表示されます。
答えるのが面倒なら、最初の2つはotherにして、最後のYes/Noだけ正直に答えておけばよいです。

In order to serve you better, please answer the following questions:
よりよいサービス提供のため、以下の質問に答えてください。
 
What company are you transferring your domain to? 
どこのレジストラににドメインを移管しますか?
 
What is the primary reason you have decided to transfer your domain? 
ドメインを移管することを決めた、一番の理由は何ですか?
 
Did you purchase your domain name at auction?
このドメイン名はオークションで購入しましたか?
 
Do you still have other domain names at NetworkSolutions.com?
あなたはNetworkSolutions.comで、他のドメイン名を持っていますか?





最終確認になります。
赤枠の2つにチェックを入れてSaveを押せばOKです。
この際、以下のように注意が出ます。書いてあるとおり数日間DNSの変更ができなくなるので、変更がいる場合は予め設定しておいてください。

NOTE: 
All Domain Name Server (DNS) changes must be completed before you request a transfer to 
Network Solutions.
Changes cannot be made to the domain name server while the transfer is in process.




注意:
(DNSサーバに対して変更が必要な場合)Network Solutionsへのドメイン移管をリクエストする前に、
すべてのドメインネームサーバ(DNS)の変更を完了しておく必要があります。
ドメイン移管手続き中は、DNSサーバに対して変更を行えません。






これでやっと完了です。
後日メールにてauth codeが送信されてきます。

Your request for an Auth Code has been received and your information will be validated to 
ensure the security of your account.
If your request is approved, you will receive your Auth Code by email in 3 days.




Auth Codeの発行リクエストを受け取りました。
これよりアカウントのセキュリティを確保するためにあなたの情報(入力された内容?)を検証します。
 
リクエストが承認されたら、AuthCodeを3日以内にメールで送信します。






連絡メールの確認


Auth Codeの発行依頼を行い、しばらくすると下記のようなメールが来ます

Domain Protect Status
 
Dear $user_name
 
We appreciate the opportunity to serve your online needs. 
We wanted to let you know that Domain Protect has been turned off for the domains listed below. 
 
Account Number: $account_no
 
Domain Name Registration: $domain_name
Update made by: $user_name
Update made: $update_by
 
Turning Domain Transfer Lock off removes an extra layer of protection against an 
unauthorized transfer of your domain name registration(s). 
 
When turned on, Domain Transfer Lock provides protection from "domain hijackers" or others 
who may illegally attempt to transfer your domain name registration.
With Domain Transfer Lock on you can still perform legal name changes and consolidate or 
move domain names between Network Solutions® accounts.
If you intend to transfer this domain name please call Network Solutions at 1-888-642-9675 
to request assistance from a transfer specialist.	
 
Thank you for choosing Network Solutions. If you have any questions or need assistance, 
please contact us at https://www.networksolutions.com/contact/index.jsp. 
You can also contact Online Support at 
https://www.networksolutions.com/help/current-support-requests.jsp. 
Again, we appreciate the opportunity to serve your online needs.




私たちはお客様のニーズをお手伝いできることに感謝しています。
この度、以下のサイトに対するDomain Protectがオフになったことをご連絡します。
 
Account Number: 
 
Domain Name Registration: 
Update made by: 
Update made: 
 
ドメイン移管のロック(Domain Transfer Lock)をオフに変更すると、登録しているドメイン名の
不正譲渡に対する追加の保護が無くなります。
 
Domain Transfer Lockをオンにしておくと、「ドメインハイジャック」の犯罪から
登録しているドメイン名の違法な転送の保護されます。
Domain Transfer Lockがオンのままでも、通常の名前変更や、Network Solutionsのアカウント間であれば
ドメイン名の移動は可能です。
このドメイン名を移管する場合は、1-888-642-9675よりNetwork Solutionsへ電話をして
専門家からの移管についてサポートを受けてしてください。
 
ネットワークソリューションを利用いただき、ありがとうございます。ご質問やサポートが必要な場合は、
https://www.networksolutions.com/contact/index.jspまでご連絡ください。
またhttps://www.networksolutions.com/help/current-support-requests.jspよりサポートへ連絡できます。
繰り返しになりますが、私たちはお客様のニーズをお手伝いできることに感謝しています。



Domain Transfer LockやDomain Protectは、他のレジストラでも提供しているサービスで、メールに記載の通り想定外の不正なドメイン移管を防ぐためのロック機能です。ロックをONにしたままでは他社へドメイン移管ができないので、OffにしてしまってOKです。(通常はONにしておいた方が安全です)

お名前.comのドメインオークションで取得したドメインが使用可能になるまで


ドメインの登録ができるサービスの、お名前.comでは、利用期限が切れたドメインを購入できるドメインオークションというものがあります。

興味があったので、試しに一回入札してみました。
人気があまりないドメインだったので、競争相手もなく1万円程度で購入できたのですが、このサービスは取得したドメインが使用できるまでに時間がかかるようです。

問い合わせしてみたところ、以下のような回答をもらいました。

バックオーダーにてご取得いただきましたドメインは、お名前.com管理ではなく、他社レジストラ管理となります。
また、レジストラは海外の管理会社の場合が多く、現在管理先レジストラのお客様アカウント作成手配中と
なっております。
 
アカウント作成にお時間がかかりますため、落札後、お客様にお渡しできるまで2週間から1,2ヶ月となります。
 
お待たせいたしまして大変申し訳ございませんが、管理先レジストラのアカウントがお手元に届くまで
今しばらくお待ちいただけますようお願い申しあげます。



長くて数か月かかるということは、すぐに作る必要のあるサイト向けのサービスではなさそうです…

チェジュ航空:会員登録で名前を間違えたときにすること

チェジュ航空の会員は、登録後に会員情報をwebから変更可能ですが、名前などの一部の情報はweb上から変更できません。webサイト上も、下記の記載があります。

会員登録の際、ローマ字の氏名は会員本人のパスポートに記載されたローマ字を姓・名に
区分して該当欄に記載してください。 (国際線搭乗記録と会員情報のローマ字の氏名が
一致しない場合、ポイント加算などの特典の提供が不可)
 
会員登録後に重要箇所に誤りがあった場合は、当社が要求する証明書類(戸籍謄本、パスポートの
コピーなど)を提出し、スタッフが確認後、登録内容の変更ができます。



もし、名前を間違えたときは、下記の手順で修正を行えます。

1.カスタマーサポートに電話する
電話番号:0570-001-132

2.最初、韓国語で案内が流れるが、下記の番号を押してオペレータにつないでもらう。
3->2->3
3番:日本語での案内を希望
2番:国際線
3番:オペレータにつなぐ

3.電話で名前の変更を依頼する。
オペレータは、日本人なのでやりとりは心配不要です。


4.下記の番号でパスポートをFaxする。(FAX番号は、電話したときに教えてもらえます)
Fax番号: 092-409-0485


注意:
チケットは、ユーザ情報が変わった後にとらないと、間違った名前で発券されてしまう。このため、飛行機に乗れない危険がある。

基本的に、Faxの内容確認後、向こうで名前の変更をしてもらう形になるので、1日程度かかる。しかし、チケットをすぐに取る必要があるなど、急ぎの場合はその旨伝えれば、先にユーザ情報だけ変更してもらうことも可能(この場合もパスポートのFax送信自体は必要)

名前が変わったかは、Webの会員方法変更画面を開くと分かる。


…な、感じっぽいです。
実際に体験したので、メモ代わりに残しておきます。

エラーの意味:암호화 작업이 진행중입니다. 확인을 누르시고 잠시 기다려 주십시오.



---------------------------
Web ページからのメッセージ
---------------------------
암호화 작업이 진행중입니다. 확인을 누르시고 잠시 기다려 주십시오.
---------------------------
OK   
---------------------------




訳:
암호화 작업이 진행중입니다.
暗号化の作業が進行中です

확인을 누르시고 잠시 기다려 주십시오.
確認をしている間、少々お待ちください

単語の意味:
암호화:暗号化
작업:作業
진행중:進行中
확인:確認
잠시:暫時(少々の意味)

[Rails]form_forで、エラー”ActionView::Template::Error (undefined method xxx_path…”が出るときすべきこと

Ruby on Railsでモデルを作り、viewの中でform_forヘルパーメソッドを利用したとき、下記のようなエラーが出る場合があります。
ActionView::Template::Error (undefined method `users_path’ for …)

このような場合は、routes.rbに下記の定義を追加するとうまくいくかもしれません。
下記は、Usersモデルを使用している場合の例です。

resources :users




参考:
http://stackoverflow.com/questions/8706774/undefined-method-with-path-while-using-rails-form-for

[CakePHP]elementの*.ctpファイルには関数を書けない

CakePHPにはviewの中で共通仕様するパーツをelementとして定義できるがこの中で、phpのfunctionを書くとエラーになる。

elementのctpファイルは、最終的にViewクラス内の_render()で読み込まれるが、この時include()を使っている。

cake/libs/view/view.php

class View extends Object {
	function _render($___viewFn, $___dataForView, $loadHelpers = true, $cached = false) {
		...
		if (Configure::read() > 0) {
			include ($___viewFn);				//  $___viewFn = "xxxxx.ctp"
		} else {
			@include ($___viewFn);
		}
 
	}
}



なので、同じctpファイルを2回includeされると、”同名の関数が複数回定義されている”とのエラーが出てしまう。

[AWS]t2インスタンスでWordPressを使うときの参考情報

めも。

t2インスタンスの性能

t2.microだと素のwordpressで1500pv/hrぐらい、
t2.smallだと素のwordpressで3000pv/hrぐらい処理できる。
静的ページならその10倍くらいはOK

CPUバーストを使い切ると…
t2.microで10%のパワーしか出ない。t2.smallだと20%。
CPUバーストを使い切るとCloudWatchのCPU Utilで10%で張り付くので、こうなったらクレジットが残っているかチェックが必要。


amimoto wordpressを使うと、チューニングされているのでさらに能力が出せる。
http://ja.amimoto-ami.com/

[Unity3D]LINQ to GameObjectの基本的な使い方

Unityで、Hierarychy上のGameObject操作を簡単に行えるAssetとして、LINQ to GameObjectというものがあります。これを使うと、ツリーの中から特定の条件に一致するGameObjectやComponentを検索する処理を簡単に書くことができます。
今回は、LINQ to GameObjectの基本的な使い方を紹介します。


まずは動作確認をかねて、基本的な使い方の説明です。
下記のコードでHierarychy上にある自陣の子孫に当たる全GameObjectを取得します。
LINQ to GameObjectを使うためには、”using Unity.Linq;”が必要なので、注意が必要です。

using UnityEngine;
using System.Collections;
using Unity.Linq;
 
public class SampleScript : MonoBehaviour {
 
    // Use this for initialization
    void Start () {
        // 自分の子に存在するすべてのGameObjectを列挙する
        foreach ( GameObject obj in this.gameObject.Descendants() ) {
            Debug.Log( obj.name );
        }
    }
}



Descendants()は、自分の子孫にあたるGameObjectを検索しますが、下記のメソッド達があります。

Ancestors();   // 祖先(親、親の親...)
Descendants(); // 子孫(子、孫...)
Parent();      // 直接の親(親の親は含まない)
Children();    // 直接の子供(孫要素は含まない)
BeforeSelf();  // 兄弟要素のうち、自分より上にあるもの
AfterSelf();   // 兄弟要素のうち、自分より下にあるもの





次は、uGUIのButtonオブジェクトだけを取得してみます。
GameObjectが持つ、特定のComponentだけを抽出するには、OfComponent()メソッドを使用します。

using UnityEngine;
using System.Collections;
using Unity.Linq;
using UnityEngine.UI;
 
public class SampleScript : MonoBehaviour {
    void Start () {
        foreach ( Button button in this.gameObject.Descendants().OfComponent<Button>() ) {
            Debug.Log( button.name );
        }
    }
}



LINQのWhere()なども使用できるので、以下のような感じで、特定の名前を持つGameObjectだけをさらに絞り込むことも可能です。LINQのWhere()は少し読みづらくて抵抗がある…という場合は、普通にforeachの中でif文を書いて絞り込んでしまってもOKです。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Linq;
using UnityEngine.UI;
 
public class SampleScript : MonoBehaviour {
    void Start () {
        foreach ( GameObject enemy in this.gameObject.Descendants().Where( x => (x.name=="enemy") ) ) {
            Debug.Log( enemy.name );
        }
    }
}



LINQ to GameObjectでは、他にDestroy()拡張メソッドも用意してくれているので、
以下のように、条件に一致するオブジェクトを一気に消すことも可能です

this.gameObject.Descendants()
        .Where( x => (x.name=="effect") )
        .Destroy();


Notoフォント:日本語のみ入った*.otfの入手方法(ハングル,中国語のみも)

Google,Adobeが作った和文フォントに、Noto Sans CJKというものがあります。

ファイルは下記の場所から取得できるのですが、CJK(中国語、日本語、韓国語)の3つが入っているため、
otfファイルのサイズが大きくなっています。
https://www.google.com/get/noto/

PCで使用する場合はこれで問題ないのですが、Androiddアプリなどのモバイル向けに利用する場合は、バイナリのサイズが大きくなってしまいます。このような場合、下記のサイトから特定の言語のフォントのみが入ったサブセットをダウンロードできます。
https://github.com/googlei18n/noto-cjk

たとえば、NotoSansCJKkr-Thin.otfは14.8MBもありますが、
日本語だけが入ったNotoSansJP-Thin.otfだと4.0MBで、なんと1/3以下のサイズになります。


特定言語のotfファイルの説明は以下のような感じです。

Region-specific OTF
===================
This packaging form provides monolingual subset versions of the fonts. There is
a separate font file for each of Simplified Chinese, Traditional Chinese, 
Japanese, and Korean. If you want to install one language only then this 
would be the option to consider. It will have the smallest space requirement.
It would also be the choice if you want to use the font on a system 
(such as Windows) that doesn't support the OTC format and can’t use the OpenType 
‘locl’ feature to select language.
 
The region-specific OTFs do not include the Monospace versions.



説明を見てわかるように、特定言語のみのサブセットotfには、等幅フォントは用意されていないので注意が必要です。

世界の文字と記号の大図鑑 Unicode 6.0の全グリフ
プログラマのための文字コード技術入門
文字コード「超」研究

Radikoolで特定の予約のみ保存フォルダを変更する

Radikoolを使っていて、特定の予約のみ保存フォルダを変更する方法です。

予約編集画面を開き、録音ファイル設定のファイル名欄にサブフォルダを指定します。
これで、特定予約のみ保存先フォルダを変えることができます。