echo("備忘録");

IT技術やプログラミング関連など、技術系の事を備忘録的にまとめています。

Xamarinの導入 その2(コーディング)

前回、エラー出まくりながらもXamarinの環境構築が何とか完了しました。
PCLはまだまだ問題ありですが、Android単体なら何とかなりそうなので、下記のサイトを参照して、Android用の簡単なサンプルを作成してみました。
sys-guard.com

まずはVSを起動して、プロジェクトから[Visual C#]]-[Android]-[Blank App(Android)]を選択。
現在Android(というかJava)を絶賛勉強中ということもあり、とりあえずソースはAndroid Studioで作成したものをそのままコピペして、いきなりビルド。

こいつ…動かないぞ!(当たり前)

まあ、そのままでは動きませんので、修正を。
とはいえ、まだまだソースの細かい部分を一から説明すると大変なので、現時点ではとりあえず感じたことを。

  • 基本的なクラスとかコントロールは、デフォルトでインポートされてるもので大丈夫っぽい。(今回個別に追加したのは「Android.Graphics」のみです。またヒントに結構「この名前空間のこのクラスを使え」って直に表示されます。)
  • プロパティ・メソッド名は同じものが多く、せいぜい大文字・小文字の違いのみ。(マウスオーバーで提示される修正で、大半のエラーは直りました。)
  • イベントリスナーとか、ダイアログとかの固定処理(onCreateDialog()など)が、ちょっとだけ違う(まあ、ここは慣れ…なのかな?)

※先程のSYSTEM GUARDIANさんのページとか、https://developer.xamarin.com/api/root/MonoAndroid-lib/さんなんかが参考になると思います。

もちろんJavaとXamarinの違いに苦戦はしましたが、何とかビルドも通り、実行。
f:id:Makky12:20161022224054j:plain
こんな感じでボタンが表示されて、クリックすると…(しかし「ここをクリック」って、1クリック詐欺かよ…)

f:id:Makky12:20161022224102j:plain
ちゃんとメッセージボックスが表示されました。

というわけで、とりあえずAndroid単体なら、何とかなりそうですね。(iOSも試せれば良いんですが…Mac購入の日は遠い)

今後は、もっと突っ込んだ所に手を出せるといいなあ。
まあ、まずはAndroid(というかJava)の勉強が先ですね。

※おまけ
・先述のSYSTEM GUARDIANさんのページにもありますが、ちゃんとGUIデザインも出来るみたいです。(Android SDKが古かったらしく、実行できなかった。)

・「フレームがモジュールにありません」と表示され、ステップ実行が出来ませんでした。実機デバッグだとこうなるんでしょうか。
あ、PCがヘボいから?(もう6年前のPCですから…報酬入ったら、DELL通販あたりで買うかな…)


あと、最後にソースコードを。

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;

using Android.Graphics;

namespace AndroidApp
{
    [Activity(Label = "AndroidApp", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity, View.IOnClickListener
    {
        private readonly int WC = LinearLayout.LayoutParams.WrapContent;
        private readonly String TAG_MESSAGE = "0";
        private readonly String TAG_YESNO = "1";
        private readonly String TAG_TEXT = "2";
        private readonly String TAG_IMAGE = "3";

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            RequestWindowFeature(WindowFeatures.NoTitle);

            LinearLayout layout = new LinearLayout(this);
            layout.SetBackgroundColor(Color.White);
            layout.Orientation = Orientation.Vertical;
            SetContentView(layout);

            layout.AddView(makeButton("ここをクリック!", TAG_MESSAGE));
        }

        private Button makeButton(String text, String tag)
        {
            Button button = new Button(this);
            button.SetText(text, TextView.BufferType.Normal);
            button.Tag = tag;
            button.SetOnClickListener(this);
            button.LayoutParameters = new LinearLayout.LayoutParams(WC, WC);

            return button;
        }

        void View.IOnClickListener.OnClick(View view)
        {
            String tag = (String)view.Tag;

            if (this.TAG_MESSAGE.Equals(tag))
            {
                MessageDialog.show(this, "メッセージボックス", "Hello World!");
            }
            else
            {
                return;
            }
        }

        public class MessageDialog : DialogFragment, IDialogInterfaceOnClickListener
        {
            public override Dialog OnCreateDialog(Bundle bundle)
            {
                var ad = new AlertDialog.Builder(this.Activity);
                ad.SetTitle(this.Arguments.GetString("title"));
                ad.SetMessage(this.Arguments.GetString("text"));
                ad.SetPositiveButton("OK", this);

                return ad.Create();
            }

            public static void show(Activity activity, String title, String text)
            {
                MessageDialog f = new MessageDialog();
                Bundle args = new Bundle();
                args.PutString("title", title);
                args.PutString("text", text);
                f.Arguments = args;

                f.Show(activity.FragmentManager, "messageDialog");
            }

            void IDialogInterfaceOnClickListener.OnClick(IDialogInterface dialog, int which)
            {
                // throw new NotImplementedException();
            }
        }
    }
}

VB6からVB.netに移植する際の注意点

なんか最近、急に感じるようになったんですが、1週間ってこんなにしんどかったっけ?
いや「精神的」になら、発病時&闘病中は死ぬほど感じてましたが、そうではなくて「肉体的」になんです。(むしろ精神的には、特に問題ないです。)

…単純に、年なんですかね。
あ~ヤダヤダ。(若いっていいなあ。)

とまあ、アラフォーおっさんの愚痴はこれぐらいにして、と。

今日「VB6のプログラムをVB.netに移植する」という業務があったんですが、そこでちょっとハマったので、備忘録的にメモ。

1.StrConv()関数
VB6の「StrConv()」関数の第2引数には色々引数を指定できますが、VB6の「vbFromUnicode」はVB.netでは使えなくなっています。
https://msdn.microsoft.com/ja-jp/library/cc437757(v=vs.71).aspx

じゃあどうやるのかと言えば、System.Text名前空間の「Encoding」クラスを使って、まずByte型の配列にして、(日本語を扱いたい場合、先にGetEncoding()メソッドでシフトJIS対応のEncodingオブジェクトを取得する必要がある。)

Dim mojiretu_string As String = "あいうえお"
Dim mojiretu_byte As Byte()
mojiretu_byte  = System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(mojiretu)

それからGetString()関数を使って、文字列に戻してあげればOK。

Dim mojiretu_moto As String = ""
mojiretu_moto  = System.Text.Encoding.GetEncoding("Shift_JIS").GetString(mojiretu_byte)

2.配列の扱い
移植対象のソースの中に、こんな処理があって、

Dim hairetsu(5) As string, max_index As integer
max_index = UBound(hairetsu)
Redim preserve hairetsu(10)

VB.netは配列のインデックスは0始まり固定って事は、他の言語(C#とかJavaとか)と共通になったんだから、max_indexは4だな。」って感じでソースを修正してたんですが…
いざデバッグすると、何度やっても、何をやっても期待した動きをしない。

最初、何が原因か分からず、結構ハマってたんですが…
まあ、原因は言うまでもなく「UBound(hairetsu)」の値です。

他のほとんどの言語(C#とかJavaとか)だと、例えば「hairetsu(5)」って定義したら、

hairetsu(0)~hairetsu(4)の5個の要素が作成される。

ですが、VB6では

hairetsu(0)~hairetsu(5)の6個の要素が作成される。

んです。

で、VB.netはというと、VB6の仕様を継承しています。(多分、互換性の関係なんでしょうね。)
だから、max_indexは「4」ではなく「5」なんです。

…という「VBC#は似てるっていうけど、過信すると痛い目にあうよ」というお話でした。

※ちなみに、VB独自の仕様に関係ないソースにするならば、配列の「length」プロパティを使い、

max_index = hairetsu.length - 1

とすべきです。

これなら、hairetsu(5)の場合

VB.netの場合:要素は6つ → hairetsu.length - 1 = 5 ← OK!
他の言語の場合:要素は5つ → hairetsu.length - 1 = 4 ← OK!

となり、どちらの場合も正常に動作します。
(極力.netや他の言語と共通のコードにしたほうが無難、ってことでしょうね。)

前のXamarinの導入でも「VBは独自で、C#とかに慣れてると難しい」って書きましたが、まさにこういう所が難しいんですよねえ…
(この件について、Twitterなどで結構反響がありました。ありがとうございます。)

【解いてみた】平成28年度秋期 応用情報技術者試験午後問題 問3(プログラミング)

まずは前回の修正。
「選択問題をどれに…」なんて書きましたが、諸事情により、応用情報シリーズは今回で最後にします。(まあ、こんなのがあと4回も続いても…って感じもしますし。)

という訳で、早くも最終回の今回は「プログラミング」です。
「魔法陣」に関するプログラム(というかアルゴリズム)ですね。

回答
※N^Xとは「NのX乗」という意味です

1.N^3

2-(1)
 イ:houjin[y][N+1]
 ウ:houjin[N+1][x]
 エ:(N+1) / 2
 オ:N^2未満である
 カ:yb-1
 キ:xb
2-(2)
 houjin[1][N+1] と houjin[N+1][1]

3.ク:N
  ケ:1

こんなところですかね。

個人的には、難易度は前回同様、あるいはそれよりもやや簡単といった感じで、今年はプログラミング問題の難易度は低めでしたね。
その分、来年は難易度が上がるかもしれませんね。

あと、個人的には今回の「地雷」はシステム開発技術な感じがするのですが、どうなんでしょうね。(僕がモジュール結合分野の勉強をサボってただけ?)

【解いてみた】平成28年度秋期 応用情報技術者試験午後問題 問1(情報セキュリティ)

実は昨日ツイートしたんですが、昨日は秋期情報処理技術者試験の試験日だったんですよね。

僕は今年の春に応用情報に合格しましたが、もう半年ですか…早いものです。(本当は秋にセスペを受ける予定でしたが、仕事関連がものすごくバタバタしすぎたのでパス。来春にデスペ、来秋にセスペを受ける予定です。)*1
熊本地震の直後の試験で、問2(経営戦略)の内容が「大地震発生時のBCP」だったので、結構ネットで話題になってましたね。(僕は選択しませんでしたが)

という訳で、今回の試験問題が発表されたので、試しに問1(情報セキュリティ)を解いてみました。
こんなもんでどうでしょうか?(注:答えが正解である保証はどこにもないです)

設問1
(1) ウ(パスワードを3回続けて…)
(2) ア、イ(IDと同じ文字列を…/英字・数字・記号が存在する…)

設問2
ウ(SSL

設問3
(1)指紋特徴点だけでは元の指紋全体を再現できないから。(25文字)
(2)d:認証に必要な情報をシステム管理者が一括管理できる(24文字)
   e:他人受入率と本人拒否率が共に低く、信頼性が高い(23文字)
   f:B

問題的には、前回より簡単になってる感じですね。(というか前回は文章の書き方が悪いような…)

残り(今のところ、アルゴリズム・DB・システム開発技術を予定。あと一問は…何にしますかね。)はまた後日。

*1:10/19追記:そういえばセスペって今回で最後で、次からは「情報処理安全確保支援士」になるんでした。そう考えると、無理にでも受けたほうが良かったのかも(まあ、そんな簡単に合格なんてできないか…)

Xamarinの導入

業務ではもっぱらVB.netなのですが、「やっぱりC#.netの方がいいなあ…」って感じながら作業してます。
昔はVB一本だったのですが、他の言語も覚えると「融通がきく」点が逆に「独特な言語」って感じてしまって、むしろコード記述が難しく感じます。


さて、そんな感じで業務でC#.netから離れているので、リハビリを兼ねてXamarinでスマホの開発でもやろうかな、と思いました。
しばらくスマホ開発からも離れていたので、こちらのリハビリにも良いかと思いまして。

1.インストール
で、インストールなのですが、ちょっとググったらこんな記事が…

ytabuchi.hatenablog.com

うーん、こりゃあ厄介そうだ…
とは言え、やらないと始まらないのですが。

とりあえず「プログラムの追加と削除」から「変更」をクリックして、

 ・Android ネイティブ開発キット (R10E、32ビット) 3GB
 ・Android SDK 1GB 未満
 ・Android SDK セットアップ (API レベル 19および21) 5GB
 ・Java SE 開発キット (7.0.550.13) 1GB

ココらへんを入れておけば大丈夫っぽい。(なお、UWPやWindows Store開発をやる場合、もっと必要です。)

あとは時間が経てば、インストール完了するはず。(まあ、これが結構時間を食うんですが…)

2.実機デバッグ環境構築
とりあえずインストールは完了しましたが、どうやらAndroidエミュレーターはクッソ重いらしく、実機デバッグにすべきとのこと。
幸いAndroidの実機は持っていたので、実機デバッグ環境を構築してみました。

Google USB Driverのインストール】
 [ツール]-[Android]-[Android SDK Manager]を選択するとAndroid SDK Managerが開くので、下の方にある[Extras]から「Google USB Driver」をインストール。

Android端末のUSBデバッグの有効化】
 [設定]-[端末情報]を開き、「ビルド番号」を連打すれば「開発者モード」になる(と思う)ので、その中の「USBデバッグを有効にする」にチェックを付ける。

android_winusb.infの変更】
 先程インストールしたGoogle USB Driverのフォルダ内に「android_winusb.inf」というファイルがあるので、この中の[Google.NTx86]と[Google.NTamd64]の2つのセクションに、以下の記載を追加する。

%SingleAdbInterface% = USB_Install, USB\VID_(自分のAndroidのVID)&PID_(自分のAndroidのPID)
%CompositeAdbInterface% = USB_Install, USB\VID_(自分のAndroidのVID)&PID_(自分のAndroidのPID)&MI_01

※自分のAndroidのVIDとPIDは「デバイスマネージャー」に表示されているAndroid端末のプロパティから[詳細情報]-[ハードウェアID]を選択すると確認することが出来ます。
android_winusb.infは管理者権限で編集ソフト(テキストエディタなど)を開かないと編集できません。

と、大抵のサイトでは「これでOK!」という事だったのですが、僕の環境ではダメで、デバイスマネージャーを確認した所、どうやらADBドライバのインストールも必要でした。

【ADBドライバのインストール】

  1. バイスマネージャでADBデバイス(「他のデバイス」に表示されていると思う)に「!」が表示されているので、右クリックから「ドライバソフトウェアの更新」を選択。
  2. 「どのような方法で…」と表示されたら、下の「コンピュータを参照して…」を選択。
  3. 「コンピュータ上のドライバ…」と表示されたら、下の「コンピュータ上のデバイスの一覧から…」を選択。
  4. 「次の一覧から…」は「すべてのデバイスを表示」を選択。し、「このハードウェアのために…」が表示されたら「ディスク使用」をクリックし、「製造元のファイルのコピー元」に、最初にインストールしたGoogle USB Driverのフォルダを指定する*1
  5. 「モデル」の一覧が表示されたら「Android ADB Interface」を選択。(このあと警告が出る場合があるが「はい」を選択でOK。)
  6. ドライバ更新が正常に終了すれば、Android実機の方で「USBデバッグを有効にしますか?(「このパソコンのRPAキーのフィンガープリント…)」という表示が出るので「OK」をクリック。(そのパソコンで今後も開発作業をするなら「このパソコンからの…」にチェックを入れておくと良いです。)

これでVSのデバッグ環境にAndroid名が表示できれば、めでたく実機デバッグが可能です!(表示されない場合、一度VSを再起動してみて下さい。)
これでバリバリ開発…


とはいかないんですよね、おそらく。


私の環境でもそうなんですが、他の方同様PCLプロジェクトを開こうとすると、原因不明のエラーが出まくりで、ネットの情報を色々調べて手は打ったんですが、まだ解決には至っていません…
(なお、下記の方が素晴らしいテンプレートを公開されています。私もこれでビルドが出来ました。)
ytabuchi.hatenablog.com

またiOSアプリは開発こそ可能ですが、結局デバッグにはMacが必要なので「それならXCodeで…」とも感じてしまいますし。
そうなるとAndroidですが、EclipseAndroid Studioに比べるとまだまだ発展途上な感は否めません。(C#Windows単体でスマホ開発が出来る、という点は魅力的ですけどね。)

とはいえ、「AndroidiPhoneなどのクロスプラットフォーム開発が可能」と言うのはやはり魅力的ですので、今後の発展に期待、って感じでしょうかね。

*1:僕の環境では「c:\android\sdk\extras\google\usb_driver」にありました。パスがわからない場合、Android SDK ManagerでGoogle USB Driverにマウオーバーすれば、パスが表示されます。

【やってみた】1時間プログラミング(ソースコード)

昨日書いた、オセロのソースコードです。

※ワークシート側の処理

Option Explicit

'「ゲーム開始」ボタンクリック処理
Private Sub CommandButton1_Click()
    
    Call Init
    
End Sub

'盤上のマスをダブルクリックしたときの処理
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

    'セルの行と列
    Dim row As Integer, col As Integer
    Dim resultValue As Boolean, resultCheckAll As Integer
    
    row = Target.row
    col = Target.Column
    
    '盤の外とか、すでに石が置いてあるマスには置けない。
    If ((8 < row) Or (8 < col)) Then
        Exit Sub
    ElseIf (CELLKIND.NOPEACE <> board(row, col)) Then
        MsgBox "すでに石がある場所には置けません。", vbOKOnly + vbExclamation, GAME_NAME
        Exit Sub
    End If

    '現在の手番のプレーヤーが、そこに石を置けるかのチェック
    resultValue = checkPutPeace(row, col, True)
    
    If resultValue Then
        '置けた場合、相手が石を置けるマスがあるかをチェック
        resultCheckAll = checkPutPeaceAllCell()
        
        If (1 = resultCheckAll) Then
        
            'マスがない場合、パス扱いにして、次の手番のプレーヤーが石を置ける益があるかチェックする。
            Dim strTeban As String
            
            If (CELLKIND.SENTE = turn) Then
                strTeban = "先手"
            ElseIf (CELLKIND.GOTE = turn) Then
                strTeban = "後手"
            End If
            
            MsgBox strTeban & "は相手の石を裏返せないので、パスします。", vbOKOnly + vbInformation, GAME_NAME
            
            turn = 3 - turn
            resultCheckAll = checkPutPeaceAllCell()
            
            If (1 = resultCheckAll) Then
                '2人共石を置けない場合は、試合終了。勝敗判定へ。
                If (CELLKIND.SENTE = turn) Then
                    strTeban = "先手"
                ElseIf (CELLKIND.GOTE = turn) Then
                    strTeban = "後手"
                End If
                
                MsgBox strTeban & "も相手の石を裏返せないので、ゲームを終了し、勝敗を判定します。", vbOKOnly + vbInformation, GAME_NAME
                Call judge
            End If
        ElseIf (-1 = resultCheckAll) Then
            'マスが全部埋まった場合、勝敗判定へ。
            Call judge
        End If
    Else
        'ダブルクリックした場所に置いても相手の石を裏返せない場合、そこには置けない。
        MsgBox "相手の石を裏返せないので、そこには置けません。", vbOKOnly + vbExclamation, GAME_NAME
    End If
    
End Sub

'石を置いた時、相手が石をおけるマスがあるかどうかをチェックする。
Private Function checkPutPeaceAllCell() As Integer

    Dim i As Integer, j As Integer
    Dim isPut As Boolean, isExistEmpty As Boolean
    
    isPut = False
    isExistEmpty = False
    
    For i = 1 To 8
        For j = 1 To 8
            
            If (board(i, j) = CELLKIND.NOPEACE) Then
                '石が置いてないマスがあったら、isExistEmptyフラグを立てる。
                '(全部のマスに石が置いてあるなら、相手の処理を行わずに勝敗判定を行えば良いから。)
                isExistEmpty = True
                isPut = checkPutPeace(i, j, False)
            End If
            
            '1つでも石を置けるマスがあるなら、そこで処理終了。(下も同じ)
            If (isPut) Then
                Exit For
            End If
        Next
        
        If (isPut) Then
            Exit For
        End If
    Next

    '戻り値の設定
    If (isPut) Then
        '石を置けるマスがある。
        checkPutPeaceAllCell = 0
    Else
       If (isExistEmpty) Then
           '相手が石を置けるマスはないが、石が置いていないマス自体はある。
           checkPutPeaceAllCell = 1
       Else
           '全部のマスが埋まっている。
           checkPutPeaceAllCell = -1
       End If
    End If
    
End Function



※標準モジュール側の処理

Option Explicit
Option Base 0

'「インデックスが有効範囲にありません」エラーのエラー番号
Const INDEX_OUT_OF_RANGE As Integer = 9
'メッセージボックスに表示するタイトル
Public Const GAME_NAME As String = "リバーシ"

'盤の状態を保持する2次元配列
Public board(1 To 8, 1 To 8) As CELLKIND
'手番の状態
Public turn As CELLKIND

'盤や手番の状態を定義してある列挙体
Public Enum CELLKIND
    NOPEACE = 0    '石がない
    SENTE = 1      '先手
    GOTE = 2       '後手
    GAME_END = -1  'ゲーム終了
End Enum

'checkReverse()で使用する、各方向のオフセット値を格納する配列
Private range_value(0 To 7)
'裏返すマス情報を保持するコレクション(裏返せるマス全て, 方向単位の裏返せるマス)
Private turnCellCollection As New Collection, turnCellCollection_tmp As New Collection

'初期化処理
Public Sub Init()
On Error Resume Next

Dim i As Integer, j As Integer

'各方向のオフセット値を設定
range_value(0) = Array(-1, -1)
range_value(1) = Array(-1, 0)
range_value(2) = Array(-1, 1)
range_value(3) = Array(0, -1)
range_value(4) = Array(0, 1)
range_value(5) = Array(1, -1)
range_value(6) = Array(1, 0)
range_value(7) = Array(1, 1)

For i = 1 To 8
    For j = 1 To 8
     
     '盤の情報を設定。
    If (((4 = i) And (4 = j)) Or ((5 = i) And (5 = j))) Then
        board(i, j) = CELLKIND.SENTE
    ElseIf (((4 = i) And (5 = j)) Or ((5 = i) And (4 = j))) Then
        board(i, j) = CELLKIND.GOTE
    Else
        board(i, j) = CELLKIND.NOPEACE
    End If
    
    Call draw(i, j)
    
    Next
Next

turn = CELLKIND.SENTE

Set turnCellCollection = New Collection
Call writeText

End Sub

'そのマスに手番の石が置けるかどうか。
'(isPutActuallyはTrueなら実際に裏返す。falseなら裏返せるかチェックするだけで、実際には裏返さない)
Public Function checkPutPeace(ByVal row As Integer, ByVal col As Integer, ByVal isPutActually As Boolean)
   
   Dim resultValue As Boolean, isExistTurn As Boolean
   Dim i As Integer, j As Integer
   
   isExistTurn = False
   
   'そもそも石があるなら、絶対に置けない。
   If (CELLKIND.NOPEACE <> board(row, col)) Then
       checkPutPeace = isExistTurn
       Exit Function
   End If
   
   For i = LBound(range_value) To UBound(range_value)
       resultValue = checkReverse(row + range_value(i)(0), col + range_value(i)(1), range_value(i)(0), range_value(i)(1), True)
       
       '石が置ける、かつ実際に裏返すなら、「裏返すマス」に「その方向の裏返せるマス」を追加。
       If resultValue Then
           If (isPutActually) Then
               For j = 1 To turnCellCollection_tmp.count
                   turnCellCollection.Add turnCellCollection_tmp(j)
               Next
           End If
           
           isExistTurn = True
       End If
       
       '「その方向の裏返せるマス」を初期化。
       Set turnCellCollection_tmp = New Collection
       
       '実際には裏返さない場合、1つでも石を置けるマスがあった時点で処理終了。(全チェックする必要はない)
       If ((Not isPutActually) And isExistTurn) Then
           Exit For
       End If
   Next
   
   If (isExistTurn And isPutActually) Then

       '実際に裏返す場合、盤の情報を更新して、手番を交代する。
       If (0 < turnCellCollection.count) Then
           
           For i = 1 To turnCellCollection.count
           
               Dim collection_val As Variant, collection_row As Integer, collection_col As Integer
               
               collection_val = turnCellCollection(i)
               collection_row = collection_val(0)
               collection_col = collection_val(1)
               
               board(collection_row, collection_col) = turn
               Call draw(collection_row, collection_col)
           Next
       End If
       
       board(row, col) = turn
       Call draw(row, col)
       
       turn = 3 - turn
       Call writeText
       
   End If
   
   '「すべての裏返せるマス」を初期化。
   Set turnCellCollection = New Collection
   checkPutPeace = isExistTurn
   
End Function

'「そのマスの石が裏返せるか」をチェックする。
'range_value_row,range_value_colはそれぞれ基準のマスから見たチェックするマスのオフセット、isFirstChackはそのマスが基準となるマスの隣かどうか。
Function checkReverse(ByVal row As Integer, ByVal col As Integer, ByVal range_value_row As Integer, ByVal range_value_col As Integer, ByVal isFirstCheck As Boolean) As Boolean
On Error GoTo checkReverseException

    Dim targetCellValue As CELLKIND
    Dim resultValue As Boolean
    
    'チェックするマスの情報を格納
    resultValue = False
    targetCellValue = board(row, col)
    
    If (isFirstCheck) Then
        '基準のマスの隣のマスが相手の石でなければ裏返せない。相手の石ならさらに次のマスを再帰処理でチェック。
        If ((turn <> targetCellValue) And (CELLKIND.NOPEACE <> targetCellValue)) Then
            turnCellCollection_tmp.Add Array(row, col)
            resultValue = checkReverse(row + range_value_row, col + range_value_col, range_value_row, range_value_col, False)
        End If
    Else
        '隣のマスではない場合
        If (turn = targetCellValue) Then
            '自分の石があったら、そこまでの石は裏返せる。(=挟んでいる状態)
            resultValue = True
        ElseIf (CELLKIND.NOPEACE = targetCellValue) Then
            '自分の石の前に何もないマスがあったら、裏返せない。
            resultValue = False
        Else
            '相手の石の場合は、さらに次のマスをチェック。
            turnCellCollection_tmp.Add Array(row, col)
            resultValue = checkReverse(row + range_value_row, col + range_value_col, range_value_row, range_value_col, False)
        End If
    End If
        
    checkReverse = resultValue
    Exit Function
    
checkReverseException:
    '「(board(row, col)の)インデックスが有効範囲にない」エラー。(一番端まで相手の石しか無い場合)。
    'その場合、もちろん裏返せない。
    If (INDEX_OUT_OF_RANGE = Err.Number) Then
        Debug.Print "abc"
        Err.Clear
        resultValue = False
    Else
        MsgBox Err.Number & " " & Err.Description
        resultValue = False
    End If
End Function

'勝敗判定
Public Sub judge()

    Dim count_sente As Integer, count_gote As Integer
    Dim strMessage As String
    
    turn = CELLKIND.GAME_END
    count_sente = countPeace(CELLKIND.SENTE)
    count_gote = countPeace(CELLKIND.GOTE)
    
    strMessage = "先手:" & count_sente & " 対  後手:" & count_gote & vbCrLf
    If (count_sente > count_gote) Then
        strMessage = strMessage & "先手の勝ち!"
    ElseIf (count_sente < count_gote) Then
        strMessage = strMessage & "後手の勝ち!"
    Else
        strMessage = strMessage & "引けわけです。"
    End If
    
    MsgBox strMessage, vbOKOnly + vbInformation, GAME_NAME
    Call writeText
    
End Sub

'tebanで指定された手番の石の数を調べる。
Private Function countPeace(ByVal teban As CELLKIND) As Integer

    Dim count As Integer, i As Integer, j As Integer
    count = 0
    
    For i = 1 To 8
        For j = 1 To 8
            If teban = board(i, j) Then
                count = count + 1
            End If
        Next
    Next
    
    countPeace = count

End Function

'盤を描画する。
Private Sub draw(ByVal row As Integer, col As Integer)
    
    If (CELLKIND.SENTE = board(row, col)) Then
        Sheets("Sheet1").Cells(row, col).Value = "○"
    ElseIf (CELLKIND.GOTE = board(row, col)) Then
        Sheets("Sheet1").Cells(row, col).Value = "●"
    Else
        Sheets("Sheet1").Cells(row, col).Value = ""
    End If

End Sub

'右フレームのテキストを描画する。
Public Sub writeText()

    If (CELLKIND.SENTE = turn) Then
        Range("J7").Value = "先手(白) の番です。"
    ElseIf (CELLKIND.GOTE = turn) Then
        Range("J7").Value = "後手(黒) の番です。"
    ElseIf (CELLKIND.GAME_END = turn) Then
        Range("J7").Value = "ゲーム終了!"
    End If
    
    Range("J3").Value = "先手(白): " & countPeace(CELLKIND.SENTE)
    Range("J4").Value = "後手(黒): " & countPeace(CELLKIND.GOTE)
    
End Sub

詰めが甘い部分もあるとは思いますが(特にcheckPutPeace()の一連の処理など)、ひとまずはこんな感じでしょうか。

http://ecx.images-amazon.com/images/I/51P83V533KL._SL75_.jpg
本格的に作るなら、こういう本で思考アルゴリズムとか勉強したら、もっと面白くなるんでしょうね。
(※上記のソースコードに、対CPU戦の機能はありません。)

【やってみた】1時間プログラミング

皆さんは、この動画を知っているでしょうか?

www.nicovideo.jp

IT系の書籍でもおなじみ、紀平拓男さんの動画で、タイトル通り「1時間以内にオセロをプログラミングしちゃおう」というものです。
一時期、IT系のニュースサイトなどでも話題になりました。

近頃は日経ソフトウェアの記事を読むたびに「ちょっとExcel VBAがおざなりになってるなあ…」と感じていたこともあったので、(無謀にも)リハビリがてら、これに挑戦してみました。

結果は…


テラ無理ゲー


確かに「石橋を叩きまくる」性格からか、決してプログラミングは早い方ではないとは自覚していましたが、流石に一時間は凄すぎます。
僕はというと、2時間でやっとそれっぽい動きをさせるのがやっとでした。(もちろんバグもある状態で)
しかも紀平さんは、環境設定(ブラウザインストールなど)からやってるし、HTML+JavaScriptで作成してたので、描画処理とかもやってるわけですから(僕はExcel VBAなので、オセロ盤の処理がJavaScriptより多少簡単に処理できる。)

いやホント、すごい人はいるもんだなあ、と実感しました。

でも、こういうすごい人がいるからこそ、刺激にもなるし勉強にもなるし、あと「○○では絶対に勝てないから、別で勝てるような事を身に付けなくちゃ」って思えるんですけどね。
それにこの業界は、面白い技術が次から次に生まれますし。

ホント、この業界を選んで良かった、って思います。
まあ「理系の大学に行って、本格的にITとか技術系の勉強をしとけばよかった」ってのは、今でも思いますけどね。

以上、本格的にITに触れたのは社会人になってからの、(遊べない文学部出身の)文系エンジニアの願望でした。


※おまけ
f:id:Makky12:20161011212933p:plain
結局3時間以上かかりましたが、ちゃんと最後まで完成させました。
ソースコードは後日アップロードしようと思います。)